简体   繁体   中英

Java ExecutorService get feedback for all tasks

I want to send email to multiple(500,1000,2000) users.

I have done that using ExecutorService .

But now I want to collect the number of successful emails sent and the number of failed emails out of total records.

I have implemented this like:

int startValue=0;
int endValue=0;
List userEmailList = getListFromDB();
ExecutorService  e = Executors.newFixedThreadPool(10);
Collection c = new ArrayList();

while (someflag) 
{  
// in MyTask class I am sending email to users.
c.add(new MyTask(startValue, endValue,userEmailList));  
}    
e.invokeAll(c);   //Here I am calling invokeall .
pool.shutdown();


public class MyTask implements Callable<String> { 
  MyTask(startValue, endValue,userEmailList){
  }

  public String call(){
//e.g.   batch 1 will have  - startValue => endValue   = 0 -100
//e.g.   batch 2 will have  - startValue => endValue   = 101 -199
//e.g.   batch 3 will have  - startValue => endValue   = 200 -299
//e.g.   batch 4 will have  - startValue => endValue   = 300 -399
//e.g.   batch 5 will have  - startValue => endValue   = 400 - 499

for(int i=startValue;i<endValue;i++){
      sendEmailToUser(userEmailList.get(i)){
}
 }

}

But future.get() returning me number of task completed. so from above code it will return me 5 task.

But I wanted output as no of failed emails and number of successful email sent.

for eg if there are 500 email users and if 20 falied , then output should be 480 success and 20 failed.

But with above code I am getting only no of task . ie 5 task

Can anybody tell me how I can get feedback from all concurrent tasks ( Not the number of tasks completed).

Your MyTask returns a String (implements Callable<String> ), which doesn't make much sense in your case. You are free to return any other type you want. Unfortunately you'll need some simple POJO to contain the results, eg:

public class Result {

    private final int successCount;
    private final int failureCount;

    public Result(int successCount, int failureCount) {
        this.successCount = successCount;
        this.failureCount = failureCount;
    }

}

And return it after given batch is done (implement Callable<Result> ). Of course your MyTask will then have to keep track of how many e-mails failed and return correct values wrapped around Result .

However I see several ways your code can be improved. First of all instead of passing startValue, endValue range to MyTask just use userEmailList.subList(startValue, endValue) - which will simplify your code a lot :

new MyTask(userEmailList.subList(startValue, endValue));
//...

public class MyTask implements Callable<Result> { 
    MyTask(userEmailList){
    }

    public Result call(){
        for(email: userEmailList) {
            sendEmailToUser(email);
            //collect results here
        }
        return new Result(...);
    }
 }

On the other hand there is nothing wrong in creating MyTask to send just one e-mail. That instead of aggregating counts in given batch you simply check the result of one task (one e-mail) - either nothing or exception (or single Boolean ). It's much easier and shouldn't be slower.

I could see that your call method is declared to return a String but your code doesn't return anything (probably incomplete snippet). And from your statement, I understand that you are returning whether the task is completed or not and not whether the mail has been sent. You could make the sendEmailToUser return the success of failure depending on whether the mail has been sent successfully and get the result using Future.get

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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