多线程实现
一、多线程的四种实现方式
1.继承Thread类(Thread实现Runnable接口)
2.实现Runnable接口
3.线程池
4.实现Callable接口
二、Callable的实现方式
首先, Java所有关于多线程的操作,都是Runnable的实现,但是Callable接口并没有继承Runnable接口,所以不能直接使用Callable实现多线程
通过查看JDK1.8文档, 可以看到Runnable有许多实现类,其中一个是FutureTask的实现类
查看源码,可以看到FutureTask类实现了RunnableFuture接口
RunnableFuture接口继承了Runnable和Future接口
再看一下FutureTask实现类的构造方法
有两个构造方法,第一个, 需要传入Runnable的实现,不是我要的
第二个,传入Callable接口的实现,通过这个构造方法,就可以通过实现Callable接口的方式实现多线程
Callable是一个函数式接口,只需要实现一个方法, call方法
三、Callable实现多线程Demo
创建一个ProjectPrice类模拟计算工程价格的业务, 实现Callable接口, 实现其中的call方法, 返回Integer类型数据
public class ProjectPrice implements Callable<Integer> {
private Integer price;
private String productName;
@Override
public Integer call() throws Exception {
if (productName.equals("材料")) {
TimeUnit.SECONDS.sleep(3);
System.out.println("正在计算材料价格");
price = 100;
}
if (productName.equals("人工")) {
TimeUnit.SECONDS.sleep(2);
System.out.println("正在计算人工价格");
price = 20;
}
return price;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
}
测试类, 创建两个线程,分别计算材料费和人工费
public class Test1 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
System.out.println("开始核算工程价格");
ProjectPrice projectPrice1 = new ProjectPrice();
projectPrice1.setProductName("人工");
//创建FutureTask,调用构造方法,传入Callable实现类
FutureTask<Integer> futureTask1 = new FutureTask<Integer>(projectPrice1);
//创建线程,传入FutureTask,开启多线程
new Thread(futureTask1).start();
ProjectPrice projectPrice2 = new ProjectPrice();
projectPrice2.setProductName("材料");
FutureTask<Integer> futureTask2 = new FutureTask<Integer>(projectPrice2);
new Thread(futureTask2).start();
//通过FutureTask的get方法,获取计算结果
Integer rengong = futureTask1.get();
Integer cailiao = futureTask2.get();
System.out.println("人工费用: " + rengong);
System.out.println("材料费用: " + cailiao);
System.out.println("共花费: " + (rengong + cailiao));
}
}
输出结果:
开始核算工程价格
正在计算人工价格
正在计算材料价格
人工费用: 20
材料费用: 100
共花费: 120
四、总结
1)不是说Java中多线程的实现都必须要实现Runnable接口吗?为什么这里只实现callable接口就可以了.
答: 在创建多线程的时候,传入到Thread构造方法中的参数是FutureTask,而FutureTask实现了RunnableFuture接口,RunnableFuture接口继承了Runnable接口,其实是间接实现了Runnable接口
2)Runnable接口必须要实现run方法,为什么没有实现run方法也可以实现多线程?
答: 因为FutureTask已经帮我们实现了run方法, 再run方法中, FutureTask会帮我们调用callable接口的call方法,所以只需要实现call方法即可
3)Runnable和Callable的区别
Runnable实现run方法,没有返回值
Runable是java.lang包下的接口
Runnable是java原生的多线程顶端接口,可以直接实现多线程
Callable实现call方法
Callable是JUC包下的接口, 更高级的接口
Callable是另外的实现多线程的方式, 和多线程之间并没有直接关系, 需要通过FutureTask中间类来实现多线程操作
Callable通过get方法获取返回值的时候,会阻塞当前主线程,直到获取到值后再继续执行主线程
笔记有误的话,请指出,谢谢