标签:his 计时 void numbers time 时间 incr return color
来自:https://www.cnblogs.com/shipengzhi/articles/2067154.html : java并发编程-Executor框架+Future
import java.util.concurrent.*; public class ConcurrentCalculator2 { private ExecutorService executorService; private CompletionService<Long> completionService; private int cpuCoreNumber; public ConcurrentCalculator2() { cpuCoreNumber = Runtime.getRuntime().availableProcessors(); executorService = Executors.newFixedThreadPool(cpuCoreNumber); completionService = new ExecutorCompletionService<Long>(executorService); } public Long sum(final int[] numbers) { for (int i = 0; i < cpuCoreNumber; i++) { // 根据CPU核心个数拆分任务,创建FutureTask并提交到Executor int increment = numbers.length / cpuCoreNumber + 1; int start = increment * i; int end = increment * i + increment; if (end > numbers.length) end = numbers.length; SumCalculator subCalc = new SumCalculator(numbers, start, end); if (!executorService.isShutdown()) { completionService.submit(subCalc); } } return getResult(); } public Long getResult() { //迭代每个只任务,获得部分和,相加返回 Long result = 0l; for (int i = 0; i < cpuCoreNumber; i++) { try { Long subSum = completionService.take().get(); result += subSum; } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } return result; } public void close() { executorService.shutdown(); } class SumCalculator implements Callable<Long> {//Runnable private int[] numbers; private int start; private int end; public SumCalculator(final int[] numbers, int start, int end) { this.numbers = numbers; this.start = start; this.end = end; } @Override public Long call() throws Exception { Long sum = 0l; for (int i = start; i < end; i++) { sum += numbers[i]; } return sum; } } public static void main(String[] args) { int[] numbers = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; ConcurrentCalculator2 calculator = new ConcurrentCalculator2(); Long sum = calculator.sum(numbers); System.out.println(sum); calculator.close(); } /** * Callable 和 Future接口 * Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。 * Callable和Runnable有几点不同: * (1)Callable规定的方法是call(),而Runnable规定的方法是run(). * (2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。 * (3)call()方法可抛出异常,而run()方法是不能抛出异常的。 * (4)运行Callable任务可拿到一个Future对象, * Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。 * 通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。 */ }
https://www.jb51.net/article/132606.htm:
我们都知道实现多线程有2种方式,一种是继承Thread,一种是实现Runnable,但这2种方式都有一个缺陷,在任务完成后无法获取返回结果。要想获得返回结果,就得使用Callable,Callable任务可以有返回值,但是没法直接从Callable任务里获取返回值;想要获取Callabel任务的返回值,需要用到Future。所以Callable任务和Future模式,通常结合起来使用。
试想一个场景:需要一个帖子列表接口,除了需要返回帖子列表之外,还需要返回每条帖子的点赞列表和评论列表。一页10条帖子来计算,这个接口需要访问21次数据库,访问一次数据库按100ms计算,21次,累计时间为2.1s。这个响应时间,怕是无法令人满意的。怎么办呢?异步化改造接口。
查出帖子列表后,迭代帖子列表,在循环里起10个线程,并发去获取每条帖子的点赞列表,同时另起10个线程,并发去获取每条帖子的评论列表。这样改造之后,接口的响应时间大大缩短,在200ms。这个时候就要用Callabel结合Future来实现。
private List<PostResponse> createPostResponseList(Page<PostResponse> page,final String userId){ if(page.getCount()==0||page==null||page.getList()==null){ return null; } //获取帖子列表 List<PostResponse> circleResponseList = page.getList(); int size=circleResponseList.size(); ExecutorService commentPool = Executors.newFixedThreadPool(size); ExecutorService supportPool = Executors.newFixedThreadPool(size); try { List<Future> commentFutureList = new ArrayList<Future>(size); if (circleResponseList != null && circleResponseList.size() > 0) { for (PostResponse postResponse : circleResponseList) { final String circleId=postResponse.getId(); final String postUserId=postResponse.getUserId(); //查评论列表 Callable<List<CircleReviews>> callableComment = new Callable<List<CircleReviews>>() { @Override public List<CircleReviews> call() throws Exception { return circleReviewsBiz.getPostComments(circleId); } }; Future f = commentPool.submit(callableComment); commentFutureList.add(f); //查点赞列表 Callable<List<CircleZan>> callableSupport = new Callable<List<CircleZan>>() { @Override public List<CircleZan> call() throws Exception { return circleZanBiz.findList(circleId); } }; Future supportFuture = supportPool.submit(callableSupport); commentFutureList.add(supportFuture); } } // 获取所有并发任务的执行结果 int i = 0; PostResponse temp = null; for (Future f : commentFutureList) { temp = circleResponseList.get(i); temp.setCommentList((List<CircleReviews>) f.get(); temp.setSupportList((List<CircleZan>) f.get(); circleResponseList.set(i, temp); i++; } } catch (Exception e) { e.printStackTrace(); } finally { // 关闭线程池 commentPool.shutdown(); supportPool.shutdown(); } return circleResponseList; }
★ 下面给出一个Executor执行Callable任务的示例代码(https://blog.csdn.net/ns_code/article/details/17465497?utm_source=blogxgwz0):
import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; public class CallableDemo{ public static void main(String[] args){ ExecutorService executorService = Executors.newCachedThreadPool(); List<Future<String>> resultList = new ArrayList<Future<String>>(); //创建10个任务并执行 for (int i = 0; i < 10; i++){ //使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中 Future<String> future = executorService.submit(new TaskWithResult(i)); //将任务执行结果存储到List中 resultList.add(future); } //遍历任务的结果 for (Future<String> fs : resultList){ try{ while(!fs.isDone);//Future返回如果没有完成,则一直循环等待,直到Future返回完成 System.out.println(fs.get()); //打印各个线程(任务)执行的结果 }catch(InterruptedException e){ e.printStackTrace(); }catch(ExecutionException e){ e.printStackTrace(); }finally{ //启动一次顺序关闭,执行以前提交的任务,但不接受新任务 executorService.shutdown(); } } } } class TaskWithResult implements Callable<String>{ private int id; public TaskWithResult(int id){ this.id = id; } /** * 任务的具体过程,一旦任务传给ExecutorService的submit方法, * 则该方法自动在一个线程上执行 */ public String call() throws Exception { System.out.println("call()方法被自动调用!!! " + Thread.currentThread().getName()); //该返回结果将被Future的get方法得到 return "call()方法被自动调用,任务返回的结果是:" + id + " " + Thread.currentThread().getName(); } }
某次执行结果如下:
从结果中可以同样可以看出,submit也是首先选择空闲线程来执行任务,如果没有,才会创建新的线程来执行任务。另外,需要注意:如果Future的返回尚未完成,则get()方法会阻塞等待,直到Future完成返回,可以通过调用isDone()方法判断Future是否完成了返回。
标签:his 计时 void numbers time 时间 incr return color
原文地址:https://www.cnblogs.com/hahajava/p/9807031.html