简体   繁体   English

Java,多线程,ExecutorService

[英]Java, Multi Threading, ExecutorService

Following is some parts of my code, which uses Threading. 以下是我的代码的某些部分,这些部分使用了线程。 The purpose is to retrieve all the records from database (approx. 5,00,000) and send them alert email messages. 目的是从数据库中检索所有记录(约5,00,000),并向其发送警报电子邮件。 The problem I am facing is the variable emailRecords becomes very heavy and too much time is taken to send email message. 我面临的问题是变量emailRecords变得非常繁重,并且花费太多时间来发送电子邮件。 How can I make it fast by using multi-threading such that 5,00,000 records are processed parallelly? 如何使用多线程来快速处理并行处理5,00,000条记录? I tried to use ExecutorService but got confused in implementing it. 我尝试使用ExecutorService,但在实现它时感到困惑。 I got mixed up in the method checkName(), getRecords() and sendAlert(). 我对方法checkName(),getRecords()和sendAlert()感到困惑。 All these 3 methods are used relevantly. 所有这三种方法都被相关地使用。 So, where to use executorService ?? 那么,在哪里使用executorService呢?

Please provide me the suggestion how to proceed with the following code and which part needs editing? 请给我建议如何继续执行以下代码,以及哪一部分需要编辑? Thanks in advance!! 提前致谢!!

public class sampledaemon implements Runnable {

    private static List<String[]> emailRecords = new ArrayList<String[]>();

    public static void main(String[] args) {
        if (args.length != 1) {
            return;
        }

        countryName = args[0];

        try {
            Thread t = null;
            sampledaemon daemon = new sampledaemon();
            t = new Thread(daemon);
            t.start();
        } catch (Exception e) {
            e.printStackTrace()
        }

    }

    public void run() {
        Thread thisThread = Thread.currentThread();
        try {
            while (true) {
                checkName(countryName);
                Thread.sleep(TimeUnit.SECONDS.toMillis(10));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void checkName(String countryName) throws Exception {
        Country country = CountryPojo.getDetails(countryName)

        if (country != null) {
            getRecords(countryconnection);
        }
    }

    private void getRecords(Country country, Connection con) {
        String users[] = null;
        while (rs.next()) {
            users = new String[2];
            users[0] = rs.getString("userid");
            users[1] = rs.getString("emailAddress");
            emailRecords.add(props);

            if (emailRecords.size() > 0) {
                sendAlert(date, con);
            }
        }
    }

    void sendAlert(String date, Connection con) {
        for (int k = 0; k < emailRecords.size(); k++) {
            //check the emailRecords and send email 
        }
    }
}

The advantage of using the FixedThreadPool is that you don't have to do the expensive process of creating the threads again and again , its done at the beginning ...see below.. 使用FixedThreadPool的优点是,您不必执行一次又一次创建线程的昂贵过程 ,它在一开始就完成了 ……请参见下文。

ExecutorService executor = Executors.newFixedThreadPool(100);

ArrayList<String> arList =  Here your Email addresses from DB will go in ;

for(String s : arList){

     executor.execute(new EmailAlert(s));

 }



public class EmailAlert implements Runnable{

  String addr;

   public EmailAlert(String eAddr){


         this.addr = eAddr;

       }


  public void run(){


     // Do the process of sending the email here..

  }

 }

From what i can tell is that you would most likely be single threaded data retrieval, and multi-threaded for the e-mail sending. 据我所知,您很有可能是单线程数据检索,而多线程则是电子邮件发送。 Roughly, you'd be cycling through your result set and building a list of records. 粗略地讲,您将循环遍历结果集并建立记录列表。 When that list hits a certain size, you make a copy and send off that copy to be processed in a thread, and clear the original list. 当该列表达到特定大小时,您将制作一个副本并发送该副本以在线程中进行处理,然后清除原始列表。 At the end of the result set, check to see if you have unprocessed records in your list, and send that to the pool as well. 在结果集的末尾,检查列表中是否有未处理的记录,并将其也发送到池中。

Finally, wait for the threadpool to finish processing all records. 最后,等待线程池完成所有记录的处理。

Something along these lines: 遵循以下原则:

protected void processRecords(String countryName) {
  ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 10, TimeUnit.SECONDS, 
        new ArrayBlockingQueue<Runnable>(5), new ThreadPoolExecutor.CallerRunsPolicy());

   List<String[]> emaillist = new ArrayList<String>(1000);

   ResultSet rs = ....

   try {
     while (rs.next()) {
        String user[] = new String[2];
        users[0] = rs.getString("userid");
        users[1] = rs.getString("emailAddress");

        emaillist.add(user);
        if (emaillist.size() == 1000) {
            final List<String[]> elist = new ArrayList<String[]>(emaillist);
            executor.execute(new Runnable() {
                public void run() {
                    sendMail(elist);
                }
            }
            emaillist.clear();
        }
     }
   }
   finally {
     DbUtils.close(rs);
   }

   if (! emaillist.isEmpty()) {
            final List<String[]> elist = emaillist;
            executor.execute(new Runnable() {
                public void run() {
                    sendMail(elist);
                }
            }
            emaillist.clear();
   }

   // wait for all the e-mails to finish.
   while (! executor.isTerminated()) {
       executor.shutdown();
       executor.awaitTermination(10, TimeUnit.DAYS);
   }


}

Creating a second thread to do all of the work in instead of doing the same work in the main thread isn't going to help you avoid the problem of filling up the emailRecords list with 5 million records before processing any of them. 创建第二个线程来执行所有工作而不是在主线程中执行相同的工作并不能帮助您避免在处理任何记录之前用500万条记录填充emailRecords列表的问题。

It sounds like your goal is to be able to read from the database and send email in parallel. 听起来您的目标是能够从数据库中读取并并行发送电子邮件。 Instead of worrying about the code, first think of an algorithm for the work you want to accomplish. 不用担心代码,首先要考虑要完成的工作的算法。 Something like this: 像这样:

  1. In one thread, query for the records from the database, and for each result, add one job to an ExecutorService 在一个线程中,查询数据库中的记录,并为每个结果向ExecutorService添加一个作业
  2. That job sends email to one person/address/record. 该工作将电子邮件发送给一个人/地址/记录。

or alternatively 或者

  1. Read records from the database in batches of N (50, 100, 1000, etc) 从数据库中以N的批次读取记录(50、100、1000等)
  2. Submit each batch to the executorService 将每批提交到executorService

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM