java 多线程开发注意事项
多线程开发的三大特性
- 有序性
- 可见性
- 对修改后的数据可以看到拥有可见性
- 原子性
- 代码在执行的时候必须一次执行完,一次成功或者是一次失败,一次线程对一段代码有掌控,就像事务里面的原子一样
线程,本地内存你,驻村交互图
在jvm中的三大特性
有序性
编译器会对代码以及指令进行编译重排.
1. 编译器优化重排
2. 指令集重排
3. 内存系统重排
经过三次重新排序经生成最终的指令集.
在单线程的执行过程中,编译器的重排不会导致结果发生变化.
可见性
jvm在执行多线程的时候会将驻村中的变量拿到线程中的内存中,如果在线程不安全的情况下,A线程在对变量进行更改的时候B线程并不知道,B线程会执行自己的更改,在这种情况下就是操作不可见.
原子性
一个操作是不可终端的,及时在多线程的环境下,一个操作开始就不会被其他线程影响.
下图中只有语句一是原子性操作
通过加锁的形式来保证线程安全
正常情况下两个线程是交替的执行,如果我们加锁两个线程在执行的时候就是串行的.
JMM定义内存访问规范
通过JMM定义内存访问规范,实现有序性可见性,原子性.
- 程序顺序原则
- 锁规则
- volatile变量规则
- 传递性规则,A先发生于B,B先发生于C那么A必然先于C
- 线程启动规则
- 会先调用线程启动中的内容
- 线程的终止
- 线程中断规则
- 对象中介规则
通过满足上面的条件来避免加锁
线程安全的基本概念
什么是线程安全?
当过多个线程访问某个类是,不管运行时环境采用何种类,调度方式或者这些线程将如何交替执行,并且在主要调用代码中不需要任何额外的同步活协同,这个类都能表现出正确的行为,那么这个类就是线程安全的.
通过加锁而实现的线程安全不能叫做线程安全.
同步机制
- 监视器所(synchronized)
- 显示锁(ReentrantLock,ReadWriteLock)
- 原子变量(atomicInteger,atomicLong,AtomicBollean)
- Volatile
- 在使用的时候一定要注意使用原子操作
note
经过jvm的优化在1.5版本之后synchronized性能已经高于显示锁了
- 增加了自旋锁等优化模式
问题:遇到同步问题如何选择具体的实现方式
舞曲:Synchronized是解决一切并发问题的最佳选择
共享的和可变的变量
保证共享使用的变量在一个线程中就可以保证线程安全.
线程封闭技术
当访问共享的可变数据时,通常需要同步.一种避免同步的方式就是不共享数据.如果仅在单线程内访问数据,就不需要同步,这种技术成为线程封闭.
将属性设置为不可变变量
当对象满足一下条件是才是不可变的:
对象创建后不可修改
对象所有的与都是final
最佳方案:使用线程安全对象是实现线程安全的最佳方法.java.util.concurrent