Runnable与Callable的区别
我们知道,创建线程的方式可以通过Thread类,Runnable接口,和Callable接口三种方式。其中Runnable和Callable是作为任务存在的。它们区别如下:
1、是否有返回值
Runnable 没有返回值,Callable有返回值
2、是否跑出异常
Runnable 没有异常,Callable有异常
3、方法不同, run(),call()
Runnable 运行的方法是run,Callable运行的方法是call
Runnable的使用方式
public class Test {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(1);
}
}).start();
}
}
Runnable直接作为Thread的参数,里面执行着线程任务。而Callable不同,它不能直接作为Thread的参数new出来,那么我们通过什么方式使用Callable呢?
Callable的使用方式
使用Callable
- 使用Callable需要一个中间件,而这个中间件便是FutureTask,它是Runnable接口的一种实现类,故它的使用方式和Runnable一样都是作为Thread的参数,而Callable则作为FutureTask的参数,这样便通过FutureTask将Callable和Thread连接起来。
Callable的优点
- 缓存: 结果缓存!效率提高N倍
结果获取会阻塞:task.get() 获取值的方法一般放到最后,保证程序平稳运行的效率,因为他会阻塞等待结果产生!
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//开启10个线程执行任务
for (int i = 1; i < 10; i++) {
//创建线程任务FutureTask
FutureTask<Integer> futureTask = new FutureTask<>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("call()");
return 1024;
}
});
// 放入Thread中使用,结果会被缓存,第一个参数是FutureTask任务,第二个参数是线程的名字
new Thread(futureTask,String.valueOf(i)).start();
// 这个get方法可能会被阻塞,如果在call方法中是一个耗时的方法,所以一般情况我们会把这个放在最后,或者使用异步通信
int result = futureTask.get();
System.out.println("返回值:" + result);
}
}
}