多线程Runnable和Callable简介笔记

多线程实现
一、多线程的四种实现方式

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方法获取返回值的时候,会阻塞当前主线程,直到获取到值后再继续执行主线程

笔记有误的话,请指出,谢谢

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章