多线程的状态转换及多线程的内存模型实现

线程的状态

线程从开始运行到消亡,可能会经历五种状态,如下图:
多线程的状态转换及多线程的内存模型实现

-初始状态:创建了一个 Thread 对象,并且该对象已经获取到了要执行的任务 Runnbale 实例;
-可运行状态:
线程在以下几种情况会转成可运行状态
1丶该线程对象已经调用了 start() 方法;
2丶线程的时间片用完;
3丶线程调用 yieId 方法;
4丶当前线程 sleep 结束;
5丶join 终止;
6丶如果线程访问的是 synchronized 方法,则表示该线程获取到方法或变量或者代码块的锁,在并发场景下,比如两个线程访问被 synchronized 修饰的代码块,则只有一个线程可以访问到,另一个线程会重新回到可运行状态
-运行状态:可运行状态的线程获取到 cpu 时间片。注:线程进入可运行状态之后,如果一直都获取不到时间片,则该线程会一直处于可运行状态,线程是否可以获取到时间片是有 cpu 决定的。
-阻塞状态:运行状态下额线程执行 sleep 或 join 方法。
-死亡状态: run 方法结束,线程进入死亡状态之后, cpu 会对该线程进行回收,避免产生线程垃圾

多线程存在的原因?

为了更好的利用 CPU,因为在 JMM(内存模型)中存在高速缓存这一层,主存并不时时都在使用,很多时候是空闲的,使用多线程只是为了更好的实现 CPU 的使用价值。

JMM模型

JMM模型(高速缓存):产生原因,计算机在运行程序时,每条指令都是在CPU中执行的,
在执行过程中势必会涉及到数据的读写。由于线程直接去主存里面获取变量的值太慢了,CPU 执行指令的速度远远大于CPU去主存上面获取变量的速度,所以在轻量级进程(线程)与主存(内核)之间引入了高速缓存这个概念,即是先把主存上面的变量缓存到高速缓存中,线程再从高速缓存中获取变量的值,由于引入了高速缓存的概念,而高速缓存是每个线程私有的,多个线程共享一个数据的时候会带来数据一致性的问题,即是如何保证在多个高速缓存中数据能够保持一致?为了解决数据一致性的问题引入了内存屏障,被 synchronized 和 volatile 修饰的变量都使用了内存屏障,对于这些变量的修改,内存屏障能够让其它线程高速缓存上从主存上读取的值失效,从而需要从新从主存上读取最新的值就能保证每次对被 synchronized 和 volatile 修饰的变量的修改都能在多线程之间保持一致。
-synchronized:
为了实现监视器的排他性监视能力(即是实现锁),java虚拟机为每一个对象和类都关联一个锁。代表任何时候只允许一个线程拥有的特权。线程访问实例变量或者类变量不需锁。 如果某个线程获取了锁,那么在它释放该锁之前其他线程是不可能获取同样锁的。当某个代码片段被 synchronized 修饰时,这个代码块称为安全区域,这个代码块对应的锁将会被**,即无论任何时刻都最多只能有一个线程可以访问该安全区域。对于 synchronized 的使用场景:
如果用在方法上,锁的是当前实例对象
如果用在同步方法块,锁是Synchonized括号里配置的对象。
如果用在静态同步方法或静态变量上,锁是当前对象的Class对象。