1.线程的生命周期状态
- NEW:一个已经创建但是没有启动的线程处于这个状态。一个线程只能处于此状态一次。
- RUNNABLE:
- 1.READY 等待被线程调度器调度成RUNNABLE状态,执行Thread.yield () 可以返回到READY
- 2.RUNNABLE 线程处于运行状态
- BLOCKED: 线程发起阻塞式IO或者申请锁时处于此状态,阻塞式IO结束或申请到锁后,回到RUANNBLE
- WAITTING : 一个线程执行了某些特定方法之后就会处于这种状态等待其他线程执行一些特定操作。使线程变成WAITTING的方法有:Object.watting(), Thread.join(), LockSupport.park()
WAITTING变成RUANNBLE的方法有:Object.notify()/notifyAll(), LockSupport.unpark(Obj)
- TIME-WAITTING:有限的等待,超时即转换为RUNNABLE
- TERMINATERD:Thread.run()正常返回或者抛出异常都会导致结束。
2.多线程编程的优势和风险
优势:
- 提高系统吞吐率:一个线程处于等待时,其他线程任然可以执行其他操作
- 提高响应性:一个请求处理慢了,并不会影响其他请求处理。
- 充分利用多核处理器资源:利用多核资源避免资源浪费
- 最小化对系统资源的使用:多线程可以利用进程申请的资源如内存空间
劣势:
- 线程安全问题:如果采取并发访问控制措施的话,容易产生数据一致性问题,如读取脏数据,丢失更新
- 线程活性问题:产生死锁,线程饥饿等问题
- 上下文切换:上下文切换会增加系统消耗
- 可靠性:多线程编程处理复杂
3.理解串行、并发、并行
串行:按照时间顺序做事情
并发:可能会以时间分片的形式,看起来在同时做几件事情。但是真正干活的可能只有一人。
并行:几个人齐头并进干几件事情
4.线程安全性
4.1 原子性
原子性比较好理解,就是不可分割的意思。如果访问一个共享变量,对于此线程以外的线程看来这个操作是不可分割的,那么该操作就具有原子性。
实现原子操作的两种方式:
1.使用锁
2.处理器提供了CAS(Compare-and-Swap)
在java中,基础类型除了long double都是原子操作,因为64位操作系统多线程可能会混合高位低位出long double结果
4.2 可见性
可见性指的是一个共享变量更新以后其他变量是否可以读取到更新到的最新值。
在java多线程中,一个共享变量更新了其他线程是不一定能获取到最新值的。
产生的原因主要是,每个核都有自己的寄存器和写缓存器,变量在A核的寄存器或写缓存器,那么线程运行在B核中读取主内存的变量时就会读取到错误的值。
4.3 有序性
有序性是指有时一个线程在A处理器上执行的内存访问操作在B处理器上看来是乱序的。
4.3.1 重排序
编译器可能会改变我们代码的编写顺序,处理器有可能也会改变这种顺序。产生原型可能是JIT、写缓冲器、高速缓存。所以重排序分为执行重排序和储存子系统重排序
4.3.1.1指令重排序
- JIT在生成汇编代码时,new对象的时候,可能先给对象引用,然后再进行初始化(指令重排序了就&#x