++i实际上是三个独立的操作
- 读取i的值
- 讲i的值加1
- 讲计算结果写入i
如果两个线程没有同步的情况对一个计数器进行递增操作可能会导致不同线程得到的值相同。
可以使用private final AtomicLong i = new AtomicLong(0); i.incrementAndGet(); i.get();
原子性:
1.竟态条件 最常见的竟态条件类型就是“先检查后执行” 通过一个可能失效的观测结果决定下一步操作,常见的比如检查文件不存在就创建文件,在创建的时候可能这个文件已经被别的程序创建了,只是检查的时候没有完成创建。从而导致各种问题
- 原子操作 对于访问同一状态的所有操作来说,是以原子的操作进行的
锁机制:
① 内置的锁机制来支持 同步代码块(Synchronized),一个作为锁的对象引用,一个作为由这个锁保护的代码块
synchronized (lock) {
//访问或修改由锁保护的共享状态
}
②可重入锁:如果某个线程试图获得一个已经由它自己持有的锁,那么就可以成功,可以避免死锁
可见性:在没有进行同步的情况下,编译器、处理器以及运行时序等都有可能进行调整(JVM可以充分利用多核处理器)
非volatile类型的long和double变量,JVM允许讲64位的读写操作分解为两个32为的操作。当读取一个非volatile类型的long类型时,如果对该变量的读写在 不同的线程中执行,那么很可能会读取某个值的高32位和另一个值的低32位。
volatile关键字:只确保可见性,不保证原子性
使用条件:
- 对变量的写入操作不依赖变量的当前值,或者能确保只有单个线程更新变量的值
- 该变量不会与其他状态变量一起纳入不变性条件中
- 访问变量时不需要加锁
网友评论