一、Runnable和Callable< V >源码
先回顾一下Runnable和Callable< V >源码吧;
//Runnable 源码
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
//Callable<V>源码
public interface Callable<V> {
//返回V对象
V call() throws Exception;
}
源码中得出基本信息:
1.Runnable和Callable< V >的源码真的是少到极致了。这应该是遵循设计原则中的接口隔离原则吧,二者都是定义了一个标准的函数,具体逻则是由其子类实现;
2.Runnable 接口中声明返回值为void的run方法;所以Runnable开启的线程犹如脱缰骏马任其驰骋难以掌控,结果导致两个问题:1).无法直接获取到线程执行执行的结果,需要借助一个全局变量;2)不能直接捕获线程执行中的异常;
正是由于Runnable的“无法无天”难以控制,所以Java中的Callable< v >应用而生;
3.在Callable< v >源码可以看到与Runnable不同的是Callable< v >接口引入泛型V,在声明的call函数返回V 并且抛出Exception真的专门应对Runnable中的没有返回值和捕获异常的个问题的。
二、Callable< V >的异步管理类Future< V >
Future< V >接口
正如上面说的与Runable相比Callable< v >开发了更多的管理操作的权限,但是Callable中只有call函数,所以Java中提供了一个Future类用于管理Callable。然而Future< V >也同样是一个接口:
//Future<V>源码
public interface Future<V> {
//取消Task线程:参数 如果是线程正在执行,是否中断;返回中断结果:ture 中断成功;false 中断失败
boolean cancel(boolean mayInterruptIfRunning);
//判断该Task是否已近取消
boolean isCancelled();
//判断该Task是否完成
boolean isDone();
//获取该线程返回的结果,如果线程为执行完阻塞,等待执行完再返回
V get() throws InterruptedException, ExecutionException;
//获取该线程返回的结果,设置超时,超时抛出Exception
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
Future< V >定义标准函数的接口,基本功能:
- 1.判断当前任务是否完成
- 2.中断当前任务,判断是否已近中断
- 3.阻塞或者设置超时,获取异步Task结果,
Future< V >的实现类FutureTask
在源码中FutureTask实现RunnableFuture< V > 接口,然而RunnableFuture< V > 同样是实现了Runnable和Future< V > 接口;按照Java的继承原则和特征, 因此FutureTask实际中实现了Future< V >接口,同时也具备了Future的所用基本功能;
三、开启Callable< V >异步线程的基本方式
首先在Java中开启异步线程都应该会想到线程池吧,Callable同样可以借助线程池进行开启关闭,其次Callable< V >异步线程的开启肯定是要借助它的实行类FutureTask,上文中已经提到的FutureTask是implements了Runnable,所以FutureTask同样可以借助Thread类包装直接执行;
1.线程池中的在ExecutorService中定义了< T > Future< T > submit(Callable< T > task)函数就是用于开始执行Callable< V >任务滴;
ExecutorService开启Callable的demo代码:
public static void main(String[] args) {
//线程池submit开启多线程
try {
CallableMThread mThread = new CallableMThread();
ExecutorService threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
Future<String> submit = threadPool.submit(mThread);
String resualt = submit.get();
System.out.println(resualt);
threadPool.shutdown();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
//内部类的实现Callable<V>开启新线程方式
class CallableMThread implements Callable<String> {
@Override
public String call() throws Exception {
// TO DO
return "ThreadID :" + Thread.currentThread().getId() + " ThreadRandom :" + (Math.random() * 1000);
}
}
2.借助Thread包装开启Callable< V >异步线程
实现Callable< T >接口多线程例子
public static void main(String[] args) {
try {
//FutureTask启动线程
CallableMThread mThread = new CallableMThread();
FutureTask<String> task = new FutureTask<String>(mThread);
new Thread(task).start();
//返回的String结果
String resualt = task.get();
System.out.println(resualt);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
//内部类的实现Callable<V>开启新线程方式
class CallableMThread implements Callable<String> {
@Override
public String call() throws Exception {
// TO DO
return "ThreadID :" + Thread.currentThread().getId() + " ThreadRandom :" + (Math.random() * 1000);
}
}
}
3.Callable< V >开启一组线程;
实际开发中有些特殊场景需求是最短时间内完协作成几个Task,最后汇总结果呈现给用户;这一类需求往往是十分重要的交互界面的需求,所以咋能不来个demo呢
public static void main(String[] args) {
try {
CallableMThread mThread = new CallableMThread();
int coreSize = Runtime.getRuntime().availableProcessors();
//创建一个线程
ExecutorService executor = Executors.newFixedThreadPool(coreSize);
//创建多个有返回值的任务
List<Future> list = new LinkedList<Future>();
for (int i = 0; i < coreSize; i++) {
FutureTask task = new FutureTask(mThread);
//执行任务并获取future
Future future = executor.submit(task);
list.add(future);
}
//关闭线程池
executor.shutdown();
//获取并发任务结果
for (Future mFuture : list) {
//Future对象获取返回值
String resualt = mFuture.get().toString();
//输出结果
System.out.printf(resualt);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
//内部类的实现Callable<V>开启新线程方式
class CallableMThread implements Callable<String> {
@Override
public String call() throws Exception {
// TO DO
return "ThreadID :" + Thread.currentThread().getId() + " ThreadRandom :" + (Math.random() * 1000);
}
}