Java并发编程基础
1 线程的简介
1.1 什么是线程
现代操作系统调度的最小单元是线程
1.2 为什么使用多线程
- 更多的处理器核心
- 更快的响应时间
- 更好的编程模型
1.3 线程的优先级
现代操作系统采用基本采用时分形式调度运行的线程,操作系统会分出一个个的时间片,线程会分配到若干个时间片,当线程的时间片用完后就会发生线程调度,并等待下次分配
线程分配到的时间片多好决定了线程使用处理器资源的多少,而线程优先级就是决定线程需要多或者少分配一些处理器资源的线程属性
注意:线程的优先级不能作为线程正确性的依赖
1.4 线程的状态
线程的运行生命周期中有6种不同的状态
Java线程状态变迁
阻塞状态是线程阻塞在进入synchronized关键字修改的方法或代码块时的状态,但是阻塞在java.concurrent包中的Lock接口的线程状态确实等待状态,因为java.concurrent包中的Lock接口对于阻塞的实现均采用LockSupport类中相关方法
1.5 Daemon线程
Daemon线程是一种支持型线程,因为它主要被用于程序中后台调度或支持型的工作
Daemon属性需要在线程启动之前设置,不能在启动之后设置
2 启动和终止线程
2.1 构造线程
2.2 启动线程
线程对象初始化后调用start方法就可以启动线程
start方法含义:当前线程同步告知Java虚拟机,只要线程规划器空闲,应立即启动调用start方法的线程
2.3 中断
中断理解为线程的一个标志位的属性,它表示一个运行中的线程是否被其他线程进行中断操作
线程通过检查自身状态是否被中断来响应,线程通过方法isInterrupted来进行判断是否被中断,也可以调用interrupted来对当前线程的中断标志位进行复位
2.4 过期的suspend、resume和stop
不建议使用的原因:suspend调用后线程不会释放线程已经占用的资源,而是占着资源 进入睡眠状态,这样容易引起死锁的问题;stop方法在终结一个线程时不会保证线程资源正常释放,通常没有给与线程释放自愿的机会,因此导致程序可能工作在不确定的状态
2.5 安全的终止线程
通过中断或者标识位的方式能够使线程在中断时有机会去清理资源,而不是武断的将线程终止
3 线程间通信
3.1 volatile和synchronized关键词
volatile用来修改字段,就是告知程序任何对该变量的访问均需要从共享内存中获取,而对他的修改必须同步刷新到共享内存中,它能够保证所有线程对变量访问的可见性
synchronized来修改方法或同步代码块的形式来使用,它主要确保多个线程在同一时刻,只能有一个线程处于方法或同步代码块中,它保证线程对变量访问的可见性和排他性
同步代码块是通过monitorenter和monitorexit指令,而同步方法则是依靠方法修饰符上的ACC_SYNCHRONIZED来完成的
同步代码块和同步方法的本质都是对一个对象的监视器进行获取,而这个获取的过程是排他性的,同一时刻只能有一个线程获取到监视器
对象、监视器、同步队列和执行线程之间的关系
任何线程对Object对象的访问,首先获得Object对象的监视器,如果获取失败进入同步队列中,线程的状态改为blocked状态,当访问Object的前驱释放了锁,则释放操作唤醒阻塞在同步队列中的线程,使其重新尝试对监视器的获取
3.2 等待/通知机制
等待通知相关方法
等待通知机制是指一个线程A调用了对象O的wait方法进入等待状态,而另外一个线程调用notify或notifyAll方法,线程A收到通知后从对象O的wait方法返回,进而进行后续的操作
wait /notify/notifyAll方法使用注意:
- 使用wait /notify/notifyAll方法时先对对象进行加锁
- 调用wait方法线程由running到waiting状态,并将当前线程放置到对象的等待队列中
- notify/notifyAll调用后,等待线程依然不会从wait返回,需要对用notify/notifyAll线程释放锁之后,等待线程才有机会从wait返回
- notify方法将等待队列中的一个等待线程从等待队列中移动到同步队列中,notifyAll将等待队列中所有的线程全部移动到同步队列中,被移动的线程状态由waiting到blocked
- 从wait方法返回的前提是获得了调用对象的锁
等待通知机制的全流程
3.3 等待/通知的经典范式
等待方原则
- 获取对象锁
- 如果条件不满足,那么调用对象的wait方法,被通知后扔要检查条件
- 如果满足则执行对应点的逻辑
伪代码
通知方原则
- 获取对象的锁
- 改变条件
- 通知所有等待在对象上的线程
伪代码
3.4 管道的输入输出流
管道的输入输出流和普通文件的输入输出流或网络的输入输出流的不同之处在于,它主要是用于线程之间的数据传输,而传输的媒介是内存
3.5 Thread.join使用
含义:当前线程A等待thread线程终止之后才从thread.join返回
管道的输入输出流和普通文件的输入输出流或网络的输入输出流的不同之处在于,它主要是用于线程之间的数据传输,而传输的媒介是内存
3.5 Thread.join使用
含义:当前线程A等待thread线程终止之后才从thread.join返回