Thread初始化过程
1.创建你的线程就是你的父线程
2.如果没有指定threadgroup,你的threadgroup就是父线程的threadgroup
3.如果没有指定daemon,你的daemon状态默认是父线程的daemon。
/**
- 只要设置了这个标志位,就代表这个线程是daemon线程,后台线程
- 非daemon,我们一般叫工作线程
- 如果工作线程(main线程)都结束了,daemon线程不会阻止jvm进程退出的
daemon线程会跟着jvm线程一起退出
*/
- 你的优先级默认是父线程的优先级
- 如果没有指定线程名称,那么默认是thread-0格式的名称
- 线程id是全局递增的,从1开始
thread的启动过程
- 一旦启动了线程, 就不能再重新启动了,多次调用start方法。因为启动了之后,threadStatus就是非0的状态,此刻就不能重新调用了
- 你启动线程之后,这个线程就会加入之前处理好的那个线程组肿
- 启动一个线程实际上走的是native方法,start0(),会实际的启动一个线程
- 一个线程启动之后会执行run()方法
join方法
1.main线程里面开启了一个线程,main线程如果对那个线程调用了join方法,那么就会导致main线程会阻塞住,他会等其他线程的代码执行结束,那个线程执行完毕,
然后main线程才会继续往下走
interrupt
interrupt,可以中断一个线程,标志位为false,isInterrupted()方法判断;
打断一个线程的休眠
在分布式系统中一半用来实现优雅退出
volatile
并发编程中,一个线程修改了变量的值,其他线程立马可以感知到。
cpu的底层缓存会导致并发问题。导致数据不一致
MESI协议,保证在cpu缓存模型下,不会出现多线程并发读写变量,没办法及时感知到
java内存模型
分为工作内存和主内存
read(从主内存中读取)
load(将主内存读取到的值写入工作内存)
use(从工作内存读取数据来计算)
assign(将计算好的值重新赋值到工作内存中)
store(将工作内存数据写入主存)
writ(将store过去的变量值赋值给主存的变量
)
并发变成的三个特性:可见性,原子性,有序性
- 可见性
上面说的就是并发的可见性问题,线程1修改的东西,对线程2是不可见的
- 原子性
以i++举例,对于i++的操作,只要多个线程并发运行来执行代码,不能保证原子性,如果保证原子性,
第一个线程i++,i=1.第二个线程,i++,i=2.
- 有序性
对于代码,同时还有一个问题是指令重排序,编译器和指令器。有时候为了提高效率,会将指令重排序,但是有时候会导致一些问题