多线程的几种方法
- 实现Runnable接口
- 实现Callable接口
- 直接使用Thread类
Callable接口可以获取返回结果
Callable接口
Thread的构造方法如图所示
可以发现,需要传入一个实现了Runnable接口的方法或者线程组,这里只关注参数为Runnable的构造方法
如果想获取线程的返回结果,需要实现Callable接口
如果想获取线程的运行状态,需要实现Future接口
最后要使用Thread类运行该方法,还需要实现Runnable接口
FutureTask
Java已经有实现了上述三种接口的类,即FutureTask
其中实现Callable方法通过构造注入实现
FutureTask用法
package com.cheng;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class FutureTaskTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// FutureTask没有无参构造方法,所以传入MyThread 即实现了Callable接口的类
FutureTask<String> futureTask = new FutureTask<>(new MyThread());
//以futureTask作为参数,构造Thread类 运行该线程
Thread thread = new Thread(futureTask, "thread-1");
thread.start();
// 返回结果通过futureTask.get()方法获取
System.out.println(futureTask.get());
}
}
// 自定义一个类实现Callable接口
class MyThread implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("----come in call()!");
return "hello, Callable";
}
}
运行结果
----come in call()!
hello, Callable
Process finished with exit code 0
FutureTask优缺点分析
优点
结合线程池使用可以大大提高程序运行效率
缺点
- get()阻塞:如果子任务执行时间过长,获取子线程执行结果的过程中,可能阻塞主线程
public class FutureTaskTest2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> futureTask = new FutureTask<>(() -> {
System.out.println(Thread.currentThread().getName() + " ----come in!");
TimeUnit.SECONDS.sleep(5);
return "task over!";
});
Thread t1 = new Thread(futureTask, "t1");
t1.start();
// 此处会阻塞
System.out.println(futureTask.get());
System.out.println("主线程做其他任务!");
}
}
- isDone()轮询耗费资源较大:
public class FutureTaskTest2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> futureTask = new FutureTask<>(() -> {
System.out.println(Thread.currentThread().getName() + " ----come in!");
TimeUnit.SECONDS.sleep(5);
return "task over!";
});
Thread t1 = new Thread(futureTask, "t1");
t1.start();
System.out.println("主线程做其他任务!");
// 此处的轮询会耗费大量的资源
while (true){
if (futureTask.isDone()){
System.out.println(futureTask.get());
break;
}else {
TimeUnit.SECONDS.sleep(1);
System.out.println("正在处理中!!");
}
}
}
}
结论:Future对结果的获取不友好,需要阻塞或者轮询才能获取!!