Java、多线程、ExecutorService

Java、多线程、ExecutorService,java,multithreading,executorservice,Java,Multithreading,Executorservice,下面是我的代码的一些部分,它使用线程。目的是从数据库中检索所有记录(约500000),并向其发送警报电子邮件。我面临的问题是,可变的emailRecords变得非常沉重,发送电子邮件需要花费太多时间。如何通过使用多线程使500000条记录并行处理来加快速度?我试图使用ExecutorService,但在实现时感到困惑。我被方法checkName()、getRecords()和sendAlert()搞混了。这三种方法都得到了相应的应用。那么,在哪里使用executorService 请为我提供如何

下面是我的代码的一些部分,它使用线程。目的是从数据库中检索所有记录(约500000),并向其发送警报电子邮件。我面临的问题是,可变的emailRecords变得非常沉重,发送电子邮件需要花费太多时间。如何通过使用多线程使500000条记录并行处理来加快速度?我试图使用ExecutorService,但在实现时感到困惑。我被方法checkName()、getRecords()和sendAlert()搞混了。这三种方法都得到了相应的应用。那么,在哪里使用executorService

请为我提供如何继续执行以下代码的建议,以及哪些部分需要编辑?提前谢谢

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 
        }
    }
}
公共类sampledaemon实现可运行{
私有静态列表emailRecords=new ArrayList();
公共静态void main(字符串[]args){
如果(args.length!=1){
返回;
}
countryName=args[0];
试一试{
线程t=null;
sampledaemon=新建sampledaemon();
t=新线程(守护进程);
t、 start();
}捕获(例外e){
e、 printStackTrace()
}
}
公开募捐{
Thread thisThread=Thread.currentThread();
试一试{
while(true){
checkName(countryName);
睡眠(时间单位为秒,toMillis(10));
}
}捕获(例外e){
e、 printStackTrace();
}
}
public void checkName(字符串countryName)引发异常{
Country Country=CountryPojo.getDetails(countryName)
如果(国家/地区!=null){
getRecords(countryconnection);
}
}
私人记录(国家/地区、连接con){
字符串用户[]=null;
while(rs.next()){
用户=新字符串[2];
用户[0]=rs.getString(“用户ID”);
用户[1]=rs.getString(“电子邮件地址”);
emailRecords.add(道具);
如果(emailRecords.size()>0){
发送警报(日期,con);
}
}
}
无效sendAlert(字符串日期、连接条件){
对于(int k=0;k
创建第二个线程来执行主线程中的所有工作,而不是在主线程中执行相同的工作,这无助于避免在处理任何记录之前用500万条记录填充
emailRecords
列表的问题

听起来你的目标是能够同时读取数据库和发送电子邮件。与其担心代码,不如先为您想要完成的工作考虑一个算法。大概是这样的:

  • 在一个线程中,查询数据库中的记录,并为每个结果向ExecutorService添加一个作业
  • 该工作向一个人/地址/记录发送电子邮件
  • 或者

  • 以N(50、100、1000等)为单位从数据库中读取记录
  • 将每个批次提交给Executor服务

  • 使用
    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..
    
      }
    
     }
    
    ExecutorService executor=Executors.newFixedThreadPool(100);
    ArrayList arList=您来自DB的电子邮件地址将进入;
    for(字符串s:arList){
    executor.execute(新的EmailAlert);
    }
    公共类EmailAlert实现可运行{
    字符串地址;
    公共电子邮件警报(字符串eAddr){
    this.addr=eAddr;
    }
    公开募捐{
    //在此处执行发送电子邮件的过程。。
    }
    }
    
    据我所知,您很可能是单线程数据检索,而电子邮件发送则是多线程的。大致上,您将在结果集中循环并建立一个记录列表。当列表达到一定大小时,您制作一个副本并发送该副本以在线程中处理,然后清除原始列表。在结果集的末尾,检查列表中是否有未处理的记录,并将其发送到池中

    最后,等待线程池完成对所有记录的处理

    大致如下:

    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);
       }
    
    
    }
    
    protectedvoidprocessrecords(字符串countryName){
    ThreadPoolExecutor executor=新的ThreadPoolExecutor(10,10,10,TimeUnit.SECONDS,
    新的ArrayBlockingQueue(5),新的ThreadPoolExecutor.CallerRunPolicy();
    List emaillist=newarraylist(1000);
    结果集rs=。。。。
    试一试{
    while(rs.next()){
    字符串用户[]=新字符串[2];
    用户[0]=rs.getString(“用户ID”);
    用户[1]=rs.getString(“电子邮件地址”);
    emaillist.add(用户);
    如果(emaillist.size()==1000){
    最终列表elist=新的ArrayList(emaillist);
    executor.execute(新的Runnable(){
    公开募捐{
    sendMail(elist);
    }
    }
    emaillist.clear();
    }
    }
    }
    最后{
    DbUtils.close(rs);
    }
    如果(!emaillist.isEmpty()){
    最终列表elist=电子邮件列表;
    executor.execute(新的Runnable(){
    公开募捐{
    sendMail(elist);
    }
    }
    emaillist.clear();
    }
    //等待所有电子邮件完成。
    而(!executor.isTerminated()){
    executor.shutdown();
    待终止执行人(10,时间单位:天);
    }
    }
    
    可能重复,因此您发布的代码根本不适合算法。您通常需要至少两个类来处理此问题:db查询逻辑(它引用了ExecutorService)和Runnable/Callable的子类,您将在第一个类中使用all实例化该子类