多线程学习和补充:接口之间的关系等等
一、概念理解
1、进程和线程
- 进程是操作系统级别的概念:
- 一个系统中可以有多个进程;
- 线程是进程中划分的概念:
- 一个进程中可以划分多个线程;
2、处理器:个数和多核:
- 一个处理器在某一个时间点上永远都只能是一个线程!即使这个处理器是多核的。
- 多核可以提升线程的执行效率,但多核不能同时运行多个线程。
- 多个处理器才能同时运行多个线程。
二、使用多线程:Runnable 接口和 Thread 类
2.1、Runnable 接口
如上:
- Runnable 是一个功能型函数(JAVA 8 新特性)。
- 它是一个接口;
- 它只定义了一个 run() 方法。
public abstract void run();
官方文档:Runnable (Java Platform SE 8 )
2.2、Thread 类
注意:Thread 类实现了 Runnable 接口。
具体类的学习挺复杂挺多的,后续再看和分析。
2.3 使用多线程
2.3.1 方式一:实现 Runnable 接口
使用步骤
- 一个类 A,实现 Runnable 接口。该类需要重写 run()方法,即为线程的实现内容;
- 创建类 A 的对象 A-1;
- 将对象 A-1 作为 Thread 类的构造函数的入参,得到一个 Thread 类对象 T-1;
- 执行 T-1对象的 start() 方法,启动线程;
- 结束
2.3.2 方式二:继承 Thread 类
使用步骤
- 一个类 T, 继承 Thread 类。该类需要重写 run()方法,即为线程的实现内容;
- 创建类 T 的对象 T-1;
- 执行 T-1对象的 start() 方法,启动线程;
- 结束
2.3.3 两种步骤的区别:
继承 Thread 类比实现 Runnable 接口简洁了一步,在于
- 继承 Thread 类会直接将 run() 方法的实现赋予到对象中。
- 但是实现 Runnable 接口需要通过对应的构造函数将 run() 方法的实现赋予到对象中。
具体的代码实现可以见原文:Java 多线程学习(一)Java 多线程入门 - 掘金
三、各接口之间的关系
各接口之间的关系:
- Callable 接口 和 Runnable 接口
- Callable 接口只有一个 call() 方法,这是一个泛型接口,call () 函数返回的类型就是传递进来的 V 类型。
- Runnable 接口只有一个 run() 方法。
- 两者无明显关系;
- Callable 接口 和 Future接口
- 如上图,两者也无明显关系
- Executor 和 Runnable接口
- 如上图,Executor 只和Runnable 有关系。execute() 方法的入参是 Runnable 。
- Executor 和 Callable 以及 Future并无明显关系;
- ExecutorService 接口
- 这是一个很神奇的接口
- 首先它继承自 Executor :意味着和 Runnable 接口有关系
- 它通过submit()方法把 Runnable 与Callable 和 Future结合了起来
- Runnable 与Callable作为方法入参,Future作为返回结果;
- 它通过invokeAll()方法把 Callable 和 Future结合了起来,而且都是List的那种;
- invokeAny()方法暂时找不到用途。
- 这是一个很神奇的接口
四、其他关系:
4.1 FutureTask 和 Future 的关系
关系如下图,FutureTask 实现了 Future 接口和 Runnable 接口。其他就是FutureTask 自己的方法,自己的实现逻辑。
注意:FutureTask 是 Future 接口的一个唯一实现类。
我们重点看下FutureTask 的调用逻辑:(其他复杂实现暂时不管。)
- 执行线程并且得到返回结果
- run() 方法负责线程调用,内部实际调用的是 Callable 接口。
- 得到调用结果后调用自己的 set() 方法
- set() 方法:将线程结果设置为自己的一个属性:outcome
- run() 方法负责线程调用,内部实际调用的是 Callable 接口。
- 取出线程结果:
- get() 方法内部实际调用自己的 report() 方法,并返回 report() 方法的返回结果;
- report() 方法:从自身的 outcome 属性取值并返回。
上述就是对于 FutureTask 的具使用逻辑
4.2 Executors 和 ScheduledThreadPoolExecutor、ThreadPoolExecutor、Executor
4.2.1 Executors 和其他的关系 :
- 从依赖关系上康,Executors和其他接口和类没什么关系。
Executors 到底是做什么的?
Executors是一个工具类,类似StringUtils等的封装。用于提供一些常用的线程池。一般网上都是说提供四种线程池:
- newCachedThreadPool:(实现是:ThreadPoolExecutor)
- newFixedThreadPool:(实现是:ThreadPoolExecutor)
- newScheduledThreadPool:(实现是:ScheduledThreadPoolExecutor)
- newSingleThreadExecutor:(实现是:ThreadPoolExecutor)
但实际上,Executors 的方法不止这些,还有很多其他方法。不知道为什么网上这样说。
可以看到,底层实现几乎都是ThreadPoolExecutor。那么为什么不直接使用ThreadPoolExecutor呢?因为 java doc 中不提倡直接用。
4.2.2 其他:ScheduledThreadPoolExecutor、ThreadPoolExecutor、Executor之间的关系:
- 首先区分接口和实现类:
- 接口:Executor、ExecutorService、ScheduledExecutorService
- 实现类:AbstractExecutorService、ThreadPoolExecutor、ScheduledThreadPoolExecutor
- 然后对实现类再做区分
- AbstractExecutorService 是线程池对象的抽象类(抽象类不能实例化)。
- ThreadPoolExecutor、ScheduledThreadPoolExecutor可以看作是 AbstractExecutorService 的子类。
五、参考:
- Java 多线程学习(一)Java 多线程入门 - 掘金
注:开始部分对于线程、进程和处理器的概念说明很棒。- Future 解析与使用 - 林老师带你学编程 - CSDN 博客
Callable 与 Runnable的关系说的很好,还有Future 和 Callable 的关系,还有ExecutorService 的关系- Java Executors 和 ThreadPoolExecutor 线程池 - xlxxcc 的专栏 - CSDN 博客
注:说明了 Executors 和 ThreadPoolExecutor 线程池的关系。- Java 并发编程:线程池的使用 - Matrix 海子 - 博客园
注:ThreadPoolExecutor 详解。