多线程学习和补充:接口之间的关系等等

一、概念理解

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 接口

使用步骤

  1. 一个类 A,实现 Runnable 接口。该类需要重写 run()方法,即为线程的实现内容;
  2. 创建类 A 的对象 A-1;
  3. 将对象 A-1 作为 Thread 类的构造函数的入参,得到一个 Thread 类对象 T-1;
  4. 执行 T-1对象的 start() 方法,启动线程;
  5. 结束

2.3.2 方式二:继承 Thread 类

使用步骤

  1. 一个类 T, 继承 Thread 类。该类需要重写 run()方法,即为线程的实现内容;
  2. 创建类 T 的对象 T-1;
  3. 执行 T-1对象的 start() 方法,启动线程;
  4. 结束

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 的调用逻辑:(其他复杂实现暂时不管。)

  1. 执行线程并且得到返回结果
    • run() 方法负责线程调用,内部实际调用的是 Callable 接口。
      • 得到调用结果后调用自己的 set() 方法
      • set() 方法:将线程结果设置为自己的一个属性:outcome
  2. 取出线程结果:
    • 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 的子类。

五、参考:

  1. Java 多线程学习(一)Java 多线程入门 - 掘金
    注:开始部分对于线程、进程和处理器的概念说明很棒。
  2. Future 解析与使用 - 林老师带你学编程 - CSDN 博客
    Callable 与 Runnable的关系说的很好,还有Future 和 Callable 的关系,还有ExecutorService 的关系
  3. Java Executors 和 ThreadPoolExecutor 线程池 - xlxxcc 的专栏 - CSDN 博客
    注:说明了 Executors 和 ThreadPoolExecutor 线程池的关系。
  4. Java 并发编程:线程池的使用 - Matrix 海子 - 博客园
    注:ThreadPoolExecutor 详解。
原文地址:https://www.cnblogs.com/buwuliao/p/11579861.html