Java多线程编程
Callable
Runnable封装了一个异步运行的任务,可以把它想象成为一个没有参数和返回值的异步方法。Callable和Runnable类似,但是有返回值,Callable接口是一个参数化的类型,只有一个方法call
public interface Callable<V>
{
V call() throws Exception
}
Future
Future可以保存异步计算的结果,可以启动一个计算,将Future对象交给某个线程,Future对象的所有者在结果计算好之后就可以获得它
Future接口具有下面的方法:
public interface Future<V>
{
V get() throws...;
V get(long timeout, TimeUnit unit) throws...;
void cancel(boolean mayInterrupt);
boolean isCancelled();
boolean isDone();
}
FutureTask包装器
可以将Callable转换成Future和Runnable,它实现了二者的接口
Callable<Integer> myComputation = ...;
FutureTask<Integer> task = new FutureTask<Integer>(myComputation);
Thread thread = new Thread(task);
thread.start();
...
Integer result = task.get(); // It `s future
调用get()方法会发生阻塞,直到结果可以获得为止。
相关事例
在Java多线程处理任务过程中,由于每一个线程处理完自身任务之后,需要将数据传出来,然后再经过整合,完成这个业务功能。
鉴于线程自身运行完毕阶段无法返回数据,可以通过Future对象交给线程,之后通过Future对象获取到计算结果
通过FutureTask包装器将Callable转换成Future和Runnable;
比如
package future;
import java.util.concurrent.*;
public class FutureTaskCount {
// 定义4个计算线程
Callable<Integer> calculate1 = new Callable<Integer>() {
private int count = 0;
@Override
public Integer call() throws Exception {
for (int i = 0; i < 4; i++) {
count++;
System.out.println("此时线程1正在运行 当前count: " + count);
Thread.sleep(1000);
}
return count;
}
};
Callable<Integer> calculate2 = new Callable<Integer>() {
private int count = 0;
@Override
public Integer call() throws Exception {
for (int i = 0; i < 4; i++) {
count++;
System.out.println("此时线程2正在运行 当前count: " + count);
Thread.sleep(1000);
}
return count;
}
};
Callable<Integer> calculate3 = new Callable<Integer>() {
private int count = 0;
@Override
public Integer call() throws Exception {
for (int i = 0; i < 4; i++) {
count++;
System.out.println("此时线程3正在运行 当前count: " + count);
Thread.sleep(1000);
}
return count;
}
};
Callable<Integer> calculate4 = new Callable<Integer>() {
private int count = 0;
@Override
public Integer call() throws Exception {
for (int i = 0; i < 4; i++) {
count++;
System.out.println("此时线程4正在运行 当前count: " + count);
Thread.sleep(1000);
}
return count;
}
};
public static void main(String[] args) {
FutureTaskCount futureTaskCount = new FutureTaskCount();
// 获取线程池
ExecutorService executorService = Executors.newCachedThreadPool();
FutureTask calculate1 = new FutureTask<Integer>(futureTaskCount.calculate1);
FutureTask calculate2 = new FutureTask<Integer>(futureTaskCount.calculate2);
FutureTask calculate3 = new FutureTask<Integer>(futureTaskCount.calculate3);
FutureTask calculate4 = new FutureTask<Integer>(futureTaskCount.calculate4);
executorService.submit(calculate1);
executorService.submit(calculate2);
executorService.submit(calculate3);
executorService.submit(calculate4);
try {
System.out.println(calculate1.get());
System.out.println(calculate2.get());
System.out.println(calculate3.get());
System.out.println(calculate4.get());
System.out.println("所有线程计算均执行完毕");
} catch (InterruptedException exception) {
exception.printStackTrace();
} catch (ExecutionException exception) {
exception.printStackTrace();
}
}
}
当所有线程的计算均完毕时候,才会打印出 "所有线程计算均执行完毕",也就是调用get()方法会发生阻塞,直到结果可以获得为止。executorService.submit
的调用,相当于启动线程操作了,以上代码中需要将call()方法overwrite。此时,每个线程可以独立运行任务。最后直接调用get()
获取每个线程计算结果
执行器(Executor)
执行器有许多方法来构建线程池,比如newCachedThread
方法构建了一个线程池,对于每个任务,如果有空闲线程可用,立即让它执行任务,如果没有可用的线程,则创建一个新线程,那么把得不到服务的任务放置到队列中。当其他任务完成以后再运行它们。
网友评论