Java并发编程学习笔记

线程池

策略

  1. 当线程数量未达到核心线程数量,直接启动一个核心线程来执行任务。
  2. 如果线程数量已达到或者超过核心线程的数量,任务被插入到任务队列中排队执行。
  3. 如果在步骤2中无法将任务插入到任务队列中,这往往是由于任务队列已满,这时候如果线程数量未达到线程池规定的最大值,会立刻启动一个非核心线程来执行任务。
  4. 如果步骤3中线程数量达到最大值,就拒绝执行此任务。

模式
并发编程中经常使用消费者和生产者模式,通过一个容器来解决生产者和消费者的强耦合问题。大多数设计模式都会找出一个第三者进行解耦。

优点

  1. 重用线程池中的线程
  2. 有效控制线程池的最大并发数
  3. 对线程进行有效的管理,并提供定时执行及制定间隔循环执行等功能。

备注
如果已知晓策略,没有必要记优点。因为优点可直接由策略推导出来。

Executor框架

Executor作为用户级的调度器,用于将任务映射为固定数量的线程。Executor框架主要由3大部分组成:

  1. 任务。包括被执行任务需要实现的接口:Runnable或Callable接口。Runnable不返回结果,而Callable返回。
  2. 任务的执行。包括任务执行机制的核心接口Executor,以及继承自Executor的ExecutorService接口。ThreadPoolExecutor及ScheduledThreadPoolExecutor实现了ExecutorService接口。ScheduledThreadPoolExecutor主要用来执行定期或延迟的任务。
  3. 异步计算的结果。包括接口Future和实现Future接口的FutureTask接口。FutureTask是一个可对任务进行状态干预的Runnable异步对象。包括超时处理/取消任务/同步状态等干预。

注意参数
keepAliveTime
线程活动保持时间。线程池中非核心的工作线程空闲后保持存活时间。默认核心线程会在线程池中一直存活,即使处于闲置状态。

线程运行状态变迁

线程运行状态变迁图

(1)BLOCKED(等待获取锁时进入的状态)
synchronized

(2)WAITING(通过wait方法进入的等待)
当wait,join,park方法调用时,进入waiting状态。前提是这个线程已经拥有锁了。进入该状态表示当前线程需要等待其他线程做出一些特定动作(通知或中断)。

blocked和waiting状态的区别是:
A、blocked是虚拟机认为程序还不能进入某个区域,因为同时进去就会有问题,这是一块临界区。
B、发生wait等操作的先决条件是要进入临界区,也就是线程已经拿到锁了,自己可能进去做了一些事情,但此时通过判定业务上的参数,发现还有一些其他配合的资源没有准备充分,那么自己就等等再做其他事情。

(3)TIMED_WAITING(通过sleep或wait timeout方法进入的限期等待的状态)
通过wait(t),sleep(t),join(t),parkNanos,parkUntil等方法进入此状态。当时间达到时触发线程回到工作状态Runnable。

Thread.yield( )方法会将当前线程的可执行时间释放,从运行中的状态变为就绪状态。

Interrupted中断

中断不属于状态,中断可以理解为线程的一个标识位属性,表示一个运行中的线程是否被其他线程进行了中断操作。

在waiting状态下,如果发生了interrupt操作,则处于该状态的线程在内部会抛出一个InterruptedException,这个异常应当在run方法内捕获,使得run方法正常地执行完成,当然捕获异常后,是决定让线程继续运行,还是结束等要根据业务场景才处理。

interrupt只对处于waiting或timed_waiting状态的线程起作用,对其他状态不起作用。

并发/并行/线程/异步

  1. 并行(parallel):在操作系统中,一组程序按独立异步的速度执行,无论从微观还是宏观,程序都是一起执行的。

  2. 并发(concurrent):在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。其中两种并发关系分别是同步和互斥:

2.1 互斥:进程间相互排斥的使用临界资源的现象,就叫互斥。
2.2 同步:进程之间的关系不是相互排斥临界资源的关系,而是相互依赖的关系。进一步的说明:就是前一个进程的输出作为后一个进程的输入,当第一个进程没有输出时第二个进程必须等待。具有同步关系的一组并发进程相互发送的信息称为消息或事件。

并行的关键是拥有同时处理多个任务的能力。而并行的关键是拥有处理多个任务的能力,不一定要同时。

  1. 线程: 线程本质上是进程中一段并发运行的代码,所以线程需要操作系统投入CPU资源来运行和调度。
    线程都拥有各自的计数器、堆栈和局部变量等属性,并且能够访问共享的内存变量。一个线程在一个时刻只能运行在一个处理器核心上。
    多线程中每个线程的处理程序依然是顺序执行。多线程可以实现线程间的切换执行。

  2. 异步:异步使用回调的方式进行处理。异步是最终目的,多线程只是我们实现异步的一种手段。

  3. 上下文切换:任务从保存到再加载的过程就是一次上下文切换。
    参考

推荐阅读更多精彩内容