java线程(Thread)解析

本分结构分两部分

  1. 常见问题
  2. 源码分析,深入了解线程状态变化

常见问题

  1. 什么是线程?
  2. 线程间如何通信?
  3. 线程如何启动中断?
  4. BLOCKED,WAITING 区别?

1. 什么是线程?

线程是操作系统调度的最小单元,也叫轻量级进程。线程拥有各自独立的计数器,堆栈和局部变量等属性,并且能够访问共享的局部变量。

2. 线程间如何通信?

Java采用共享内存模型实现线程间通信,因此共享内存那部分就是并发需要考虑的。

java线程(Thread)解析_第1张图片
png.jpg

所有实例域,静态域和数组元素都存储在堆内存中,堆内存在线程中共享(因此并发安全主要是针对这部分内存的操作)。 局部变量,方法定义参数和异常处理器参数不会在线程中共享,它们不会有内存可见性问题,也不受内存模型的影响。

3. 线程如何启动中断?

  • 启动:启动一个线程前,最好为线程设置有意义的线程名称,方便线程问题排查(如果是线程池,则应该在自定义线程工厂中设置线程名称)。
  • 中断:中断可以理解为线程的一个标识位属性(仅仅是一个标识),他标识一个运行中的线程能否被其他线程执行了中断操作。好比其他线程对该线程打了个招呼而已。至于该线程是否真的停止运行或抛出异常,是由其内部逻辑决定,而非中断标识的设置。具体参考下方源码解析interrupt方法。

4. BLOCKED,WAITING 区别

当线程试图获取一个内部的对象锁(Sychronized, 不是java.util.concurrent库中的锁),而锁被其它线程占有,则该线程进入阻塞状态。

当线程等待另外一个线程通知调度器的一个条件的时候,它自己进入等待状态。如:在调用Object.wait()或Thread.join()方法,或者等待java.util.concurrent库中的Lock或Condition时。

两者的区别是: 进入waiting状态是线程主动的, 而进入blocked状态是被动的. 更进一步的说, 进入blocked状态是在同步(synchronized代码之外), 而进入waiting状态是在同步代码之内.

源码分析

1. 重要方法

基础概念

  • 当前执行线程
    Thread 中方法如:sleep, yield等只对当前执行线程使用,不要通过线程对象调用执行如:
    错误使用:
    Thread thread = new Thread();
    thread.start();
    thread.sleep(1000);
   正确: 在当前线程中使用
   Thread.sleep(1000);

1.1 sleep (休眠)

暂停当前执行线程一段时间。如果当前线程获取到的有锁,sleep不会让出锁。 (这个好理解,为了暂停时间的精准控制)

1.2 yield (让步)

提示系统调度器当前执行线程可让出时间片,但未做强制要求,系统可忽略此提示。所以不建议程序在处理线程调度时使用此方法。

使用方式
  1. 测试阶段用于复现由线程竞争引起的问题。
  2. 设计并发控制实现

1.3 join (连接)

主要作用就是同步,它可以使得线程之间的并行执行变为串行执行。

使用方式
  1. 在A线程中调用了B线程的join()方法时,表示只有当B线程执行完毕时,A线程才能继续执行。
原理

join方法的原理就是调用相应线程的wait方法进行等待操作。例如A线程中调用了B线程的join方法,则相当于在A线程中调用了B线程的wait方法,当B线程执行完(或者到达等待时间),B线程会自动调用自身的notifyAll方法唤醒A线程,从而达到同步的目的。

1.4 interrupt(中断)

线程的中断(interrupt)只是设置了线程的中断状态,不能简单认为是停止线程。

一个线程对象上调用interrupt()方法,只设置了中断标志位,真正有影响的是wait,join,sleep方法,以及可中断的通道上的 I/O 阻塞操作方法,当然包括它们的重载方法。这些方法会抛出InterruptedException, 而不是interrupt()。

注,获锁的阻塞过程中是不能被中断的。

使用方式
  1. 不仅仅是停止,还可以是唤醒。如 Thread.sleep(一天),突然想提前结束,调用interrupt()方法就是唯一手段,只有改变它的中断状态,让它从sleep中将控制权转到处理异常的catch语句中,然后再由catch中的处理转换到正常的逻辑。同样,对于join中的线程你也可以这样处理。
原理

如果一个线程处于了阻塞状态(如线程调用了thread.sleep、thread.join、thread.wait、1.5中的condition.await、以及可中断的通道上的 I/O 操作方法后可进入阻塞状态),则在线程在检查中断标示时如果发现中断标示为true,则会在这些阻塞方法(sleep、join、wait、1.5中的condition.await及可中断的通道上的 I/O 操作方法)调用处抛出InterruptedException异常,并且在抛出异常后立即将线程的中断标示位清除,即重新设置为false。抛出异常是为了线程从阻塞状态醒过来,并在结束线程前让程序员有足够的时间来处理中断请求。

你可能感兴趣的:(java线程(Thread)解析)