这里主要是对Callable使用方式的总结
一、Thread的使用
Thread thread = new Thread();
thread.start();
二、Runable的使用
private void test(){
new Thread(new MyRunnable()).start();
}
class MyRunnable implements Runnable{
@Override
public void run() {
//TODO 编写逻辑
}
}
三、Callable的使用
Callable< T >要与Feture< T >一起使用,适用于Java SE5 之上。
下面举几个例子:
1、基本用法:
private void test() throws Exception{
CallableTest taskWithResult = new CallableTest();
//FutureTask的众多实现接口中有一个是Future接口
FutureTask<String> futureTask = new FutureTask<String>(taskWithResult);
new Thread(futureTask).start();
//get()方法如果有结果会立刻得到,如果暂时没有结果则会一直阻塞等待线程完成
String value = futureTask.get();
System.out.println("结果:"+value);
}
class CallableTest implements Callable<String>{
@Override
public String call() throws Exception {
return "返回结果";
}
}
2、添加到线程池:
private void test() throws Exception{
ExecutorService executorService = Executors.newSingleThreadExecutor();
CallableTest taskWithResult = new CallableTest();
Future<String> future = executorService.submit(taskWithResult);
executorService.shutdown();
//get()方法如果有结果会立刻得到,如果暂时没有结果则会一直阻塞等待线程完成
String value = future.get();
System.out.println("结果:"+value);
}
class CallableTest implements Callable<String>{
@Override
public String call() throws Exception {
return "返回结果";
}
}
3、添加多个任务到线程池中:
private void test(){
//暂时没想到怎么动态获取线程数量,ThreadPoolExecutor里面有一些方法可以参考获取,但是并不能保证总是正确
//在ExecutorCompletionService源码里的样例是通过自己维护一个集合,来进行数量的判断
ThreadPoolExecutor es = (ThreadPoolExecutor) Executors.newCachedThreadPool();
CallableTest taskWithResult = new CallableTest();
CompletionService<String> cs = new ExecutorCompletionService<String>(es);
cs.submit(taskWithResult);//添加第一个任务
cs.submit(taskWithResult);//添加第二个任务
es.shutdown();
for (int i = 0;i < 2;i++){
try {
Future<String> future = cs.take();
String value = future.get();
System.out.println("结果:"+value);
}catch (InterruptedException | ExecutionException e){
e.printStackTrace();
}
}
}
class CallableTest implements Callable<String>{
@Override
public String call() throws Exception {
return "返回结果";
}
}
Callable使用的场景:
假如在主线程里面要执行一个耗时操作(暂时认为A),这个耗时操作执行完之后拿到结果又回主线程进行下一步操作(暂时认为C)。在子线程执行耗时操作的同时主线程还在执行任务(暂时认为B)。要求就是任务B要在任务A和任务C都执行完之后执行。这种方式使用Callable的话就比较合适,下面画了一个草图: