java多线程基础
java多线程基础
线程安全性
当多个线程访问莫个类时,这个类始终都能表现出正确的行为,那么这个类就是线程安全的。
在线程安全的类中封装了必要的同步机制,因此客户端无须进一步采取同步措施。
无状态对象一定是线程安全的。
保证线程安全性的三种方式
- 不在线程之间共享状态变量
- 将状态变量修改为不可变
- 访问状态变量时使用同步
原子性
在单核CPU中, 能够在一个指令中完成的操作都可以看作为原子操作, 因为中断只发生在指令间。
java中对于非long和double基本数据类型的”简单操作”都可以看作是原子的。
long和double都是64位,jmm不保证操作的原子性。
可见性
变量读取到的值,总是任何线程对该变量最后写入的值。
加锁不只局限于互斥行为,还包括了内存可见性。为了确保所有线程都能共享到变量最新的值,因此读或者写都必须在一个锁上同步。
顺序性
在Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。
Java内存模型具备一些先天的“有序性”,即不需要通过任何手段就能够得到保证的有序性,这个通常也称为 happens-before 原则。
如果两个操作的执行次序无法从happens-before原则推导出来,那么它们就不能保证它们的有序性,虚拟机可以随意地对它们进行重排序
线程封闭和栈封闭
线程封闭:变量只属于某个线程,例如通过 ThreadLocal来保持的线程变量。
栈封闭是线程封闭的一种特例,在栈封闭中,只有通过局部对象才能访问对象。
不变性
不可变的对象一定是线程安全的。不可变不等于final,即使对象所有的域都是final的,对象也依然可能是可以变得。
final 修饰引用类型只代表该引用不可变,不代表引用的对象不可变。final修饰简单值类型能保证是不可变的。
满足一下条件对象才是不可变的。
- 对象创建以后不可以修改
- 对象创建以后不可以修改
- 对象是正确创建的(this没有溢出)