前言
前面我们已经介绍了两种多线程的实现方式Java中的多线程(1), 现在接着总结第3种实现方式.
当我们需要获得线程中的返回值的时候可以使用下面的方式来实现.
二, 能获得返回值的多线程
如果要获得线程处理的返回值需要用到Callable接口, 使用ExecutorService来管理, 返回值由Future对象来处理.
- 创建task类, 实现Callable接口, 重写run方法;
- 创建线程池, 获得ExecutorService对象;
- 将我们创建的线程对象作为参数传入到submit方法中;
- 获得返回值Future对象;
代码如下
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadMain02 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
try {
for(int i=0;i<5;i++) {
Future<String> future = executorService.submit(new ThreadCallable01());
System.out.println(future.get().toString());
}
}catch(Exception e) {
e.printStackTrace();
}finally {
executorService.shutdown();
}
}
}
class ThreadCallable01 implements Callable<String> {
private Integer total;
@Override
public String call() throws Exception {
return Thread.currentThread().getName()+" -- is running";
}
}
获取线程中的返回值
在我们获取线程中的返回值的时候, 可以自己创建一个Future的list来保存获得返回值的集合, 但是当有线程没有获得返回值的时候会产生线程的阻塞, 导致后面完成的任务不能及时得到结果, 直到该线程得到返回结果位置.
为了解决这种情况, 可以使用ExecutorCompletionService来获得获结果集;
运行下面的代码:
package com.test;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadMain03 {
public static void main(String[] args) {
int threads = 10;
ExecutorService es = Executors.newFixedThreadPool(threads);
ExecutorCompletionService<String> completionService = new ExecutorCompletionService<String>(es);
try {
for(int i=0;i<5;i++) {
completionService.submit(new TaskCallable03((threads-i),i));
}
for(int i=0;i<5;i++) {
System.out.println("i="+i+" -- "+completionService.take().get());
}
}catch(Exception e) {
e.printStackTrace();
}finally {
es.shutdown();
}
}
}
class TaskCallable03 implements Callable<String> {
private int time;
private int num;
public TaskCallable03(int time, int num) {
this.time=time;
this.num = num;
}
@Override
public String call() throws Exception {
Thread.sleep(time);
return Thread.currentThread().getName()+" -- is running" + " -- num="+num;
}
}
返回的结果
i=0 -- pool-1-thread-1 -- is running -- num=0
i=1 -- pool-1-thread-5 -- is running -- num=4
i=2 -- pool-1-thread-4 -- is running -- num=3
i=3 -- pool-1-thread-3 -- is running -- num=2
i=4 -- pool-1-thread-2 -- is running -- num=1
从上面的运行结果, 并且结合ExecutorCompletionService的代码:
ExecutorCompletionService中有一个BlockingQueue队列, 实现的是LinkedBlockingQueue链表结构的队列,
先执行完的, 先放到ExecutorCompletionService对象的结果集中, 这样就避免了前面的结构没有执行完成导致的阻塞效应.
参考了许多大牛的博客, 如有不当地方, 欢迎告知, 谢谢.