面试题:几种方式获得多线程?
此时如果你答两种:Runnable和继承Thread,这是不行的,正确答案应该是:
- 传统的是继承thread类和实现runnable接口
- JDK1.5 以后又有通过实现callable接口和线程池获得
Callable和Runnable对比
我们都熟悉Runnable接口,只要继承了这个类,并重写其Run方法,就可以通过Thread的构造器传入Runnable实例来启动一个多线程:
class MyThread1 implements Runnable{
@Override
public void run() {
System.out.println("lalala");
}
}
而Callable是怎么做的呢:
class MyThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("....come in here");
return 1024;
}
}
区别如下:
- Callable有返回值,Runnable没有返回值
- Callable抛出异常,Runnable不抛异常
- Callable实现的是Call方法,Runnable实现的是Run方法
总结:Callable接口,是Runable接口的增强版。同样用Call()方法作为线程的执行体,增强了之前的run()方法。因为call方法可以有返回值,也可以声明抛出异常。
Callable怎么用?
如果你想用之前的流程,通过Thread类的构造器来创建线程,然后start那么就错了。我们看一下Thread类的构造器:
通过构造方法可以看出:Thread类并不允许我们传入一个Callable接口来创建线程,那么应该怎么做呢:答案是找一个中间人,这个中间人可以将Callable接口和Runnable接口关联起来
FutureTask 是什么
- 字面理解:未来的任务
- 用它就干一件事,异步调用
- 在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些作业交给Future对象在后台完成,
当主线程将来需要时,就可以通过Future对象获得后台作业的计算结果或者执行状态。 - 老师上着课,口渴了,去买水不合适,讲课线程继续,我可以单起个线程找班长帮忙买水,水买回来了放桌上,我需要的时候再去get。
FutureTask是Future接口的实现类,用它能帮我们解决异步调用的问题。
java5提供了Future接口来代表Callable接口里的call()方法的返回值,并为Future接口提供了一个FutureTask实现类,该实现类实现了Future接口,并实现了Runnable接口,所以这样可以作为Thread的target
看一下FutureTask的继承关系:
发现它同时实现了Runnable接口,并且看一下它的构造器:
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
那么只要我们通过FutureTask对象,就可以传入我们的Callable接口,从而通过Thread来启动一个线程了。
实例代码
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> futureTask = new FutureTask<>(new MyThread2());
new Thread(futureTask,"zhang3").start();
while(!futureTask.isDone()){
System.out.println("***wait");
}
System.out.println(futureTask.get());
System.out.println(Thread.currentThread().getName()+" come over");
}
class MyThread2 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName()+"come in callable");
return 200;
}
}