多线程Executors

在Java 5之后,任务分两类:一类是实现了Runnable接口的类,一类是实现了Callable接口的类。两者都可以被ExecutorService执行,但是Runnable任务没有返回值,而Callable任务有返回值。并且Callable的call()方法只能通过ExecutorService的submit(Callable<T> task) 方法来执行,并且返回一个 <T>Future<T>,是表示任务等待完成的 Future。

Callable接口类似于Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常而Callable又返回结果,而且当获取返回结果时可能会抛出异常。Callable中的call()方法类似Runnable的run()方法,区别同样是有返回值,后者没有。

当将一个Callable的对象传递给ExecutorService的submit方法,则该call方法自动在一个线程上执行,并且会返回执行结果Future对象。同样,将Runnable的对象传递给ExecutorService的submit方法,则该run方法自动在一个线程上执行,并且会返回执行结果Future对象,但是在该Future对象上调用get方法,将返回null。

static class CalcTask implements Callable<List<KeywordCategoryRelated>>{

        private List<KeywordCategoryRelated> keyCateList;

        private String addressIp;

        public CalcTask(String addressIp,List<KeywordCategoryRelated> keyCateList){

            this.keyCateList = keyCateList;

            this.addressIp = addressIp;

        }

       

        @Override

        public List<KeywordCategoryRelated> call() throws Exception {

           for(KeywordCategoryRelated item : keyCateList){

                    String imgUrl = RestRequestUtil.getProductImgUrl(item.getCategoryId(),item.getKeyword(),addressIp);

                        if("error".equals(imgUrl)){

                                   // 如果超时或者报错则重试一次(正常返回不重试)

                                  imgUrl = RestRequestUtil.getProductImgUrl(item.getCategoryId(),item.getKeyword(),addressIp);

                        }

                        item.setImgUrl(imgUrl);

           }

           return keyCateList;

        }

       

}

 

 

 

ExecutorService es = Executors.newFixedThreadPool(ThreadNum);

CompletionService<List<KeywordCategoryRelated>> completionService = new ExecutorCompletionService<List<KeywordCategoryRelated>>(es);

                         try {

                                 for(List<KeywordCategoryRelated> item : categoryRelatedTempSet){

                                          String addressIp = addressList.get(countIp % addressList.size());

                                          countIp++;

                                          CalcTask calcTask = new CalcTask(addressIp, item);

                        completionService.submit(calcTask);

                        logger.info("submit " + num + " success");

                                 }

                                 for(List<KeywordCategoryRelated> item : categoryRelatedTempSet){

                                          Future<List<KeywordCategoryRelated>> feature = completionService.take();

                                          List<KeywordCategoryRelated> categoryRelatedTempList = feature.get();

                                          result.addAll(categoryRelatedTempList);

                                          logger.info("get " + num + " success");

                                 }

                         } catch (Exception e) {

                                 es.shutdown();

                                 logger.info("获取图片多线程失败,计算已退出...");

                e.printStackTrace();

                return false;

            }

            es.shutdown();

 

import java.util.ArrayList;
import
java.util.List;
import
java.util.concurrent.*;

public class
Main {
   
static class Calcuete implements Callable<String>{
       
private String name;
        public
Calcuete(String name){
           
this.name = name;
       
}

       
@Override
       
public String call() throws Exception {
           
return name;
       
}
    }

   
public static void main(String[] args) {
        List<String> nameList =
new ArrayList<String>();
        for
(int i = 0;i<10;i++){
            nameList.add(
"azure" + i);
       
}
       
int thredNum = nameList.size();
       
/**********ExecutorService提交**********/
       
ExecutorService es1 = Executors.newFixedThreadPool(thredNum);
       
List<Future<String>> futureList = new ArrayList<Future<String>>();
        for
(String name : nameList) {
            Calcuete calcuete =
new Calcuete(name);
           
Future<String> future = es1.submit(calcuete);
           
futureList.add(future);
       
}
       
while(thredNum > 0){
           
for(Future<String> future : futureList){
                String result =
null;
                try
{
                    result = future.get(
0, TimeUnit.SECONDS);
               
} catch (InterruptedException e) {
                    e.printStackTrace()
;
               
} catch (ExecutionException e) {
                    e.printStackTrace()
;
               
} catch (TimeoutException e) {
                   
//超时不处理
               
}
               
if(result != null){
                    futureList.remove(future)
;
                   
thredNum--;
                    break;
               
}
            }
        }
       
/**
         *
这两者最主要的区别在于submittask不一定是按照加入自己维护的list顺序完成的。
         从
list中遍历的每个Future对象并不一定处于完成状态,这时调用get()方法就会被阻塞住,
         如果系统是设计成每个线程完成后就能根据其结果继续做后面的事,这样对于处于
list后面的
         但是先完成的线程就会增加了额外的等待时间。
         而
CompletionService的实现是维护一个保存Future对象的BlockingQueue。只有当这个
        
Future对象状态是结束的时候,才会加入到这个Queue中,take()方法其实就是Producer-Consumer
        
中的Consumer。它会从Queue中取出Future对象,如果Queue是空的,就会阻塞在那里,
         直到有完成的
Future对象加入到Queue中。
         所以,先完成的必定先被取出。这样就减少了不必要的等待时间
        
*/

        /**********CompletionService
提交**********/
       
int thredNum1 = nameList.size();
       
ExecutorService es = Executors.newFixedThreadPool(thredNum1);
       
CompletionService<String> completionService = new ExecutorCompletionService<String>(es);
        for
(String name : nameList) {
            Calcuete calcuete =
new Calcuete(name);
           
completionService.submit(calcuete);
           
Future<String> future = es.submit(calcuete);
           
futureList.add(future);
       
}
       
for(String temp : nameList) {
           
try {
                Future<String> future = completionService.take()
;
               
String name  = future.get();
               
System.out.println(name);
           
} catch (Exception e) {
                e.printStackTrace()
;
               
es.shutdown();
           
}
        }
        es.shutdown()
;
   
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值