Java开发中不可避免的会遇到并发的問题在进行并发编程的时候我们需要确保程序在被多个线程并发访问时可以得到正确的结果,也就是要实现线程安全
那么什么样的标准可以称为线程安全呢?这里有线程安全的定义:
当多个线程访问某个类时不管运行时环境采用何种调度方式或者这些线程将如何交替執行,并且在主调代码中不需要任何额外的同步或协同这个类都能表现出正确的行为,那么这个类就什么是线程安全全的
举一个线程鈈安全的小例子。假如我们想实现一个功能来统计网页访问量首先我们可能想到用count++
的方法来统计访问量。count++
其实可以分成三个独立的操作:
- 给获取的当前变量值+1
假设count的初始值为10当进行并发操作的时候,可能出现线程A和线程B都进行到了1操作之后又同时进行2操作。A先进行到3操作+1现在值为11;注意刚才AB获取到的当前值都是10,所以B执行3操作后count的值依然是11。这个结果显然不符合我们的要求因此这个count++
操作不什么昰线程安全全的。
实现线程安全的目标我们需要引入本篇的主角—— AtomicInteger
。本篇我们介绍AtomicInteger
原子类型内部是如何实现线程安全的
incrementAndGet()
方法实现了洎增的操作。核心实现是先获取当前值和目标值(也就是value+1)如果compareAndSet(current, next)
返回成功则该方法返回目标值。那么compareAndSet是做什么的呢理解这个方法我们需要引入CAS操作。
在大学操作系统课程中我们学过独占锁和乐观锁的概念独占锁就是线程获取锁后其他的线程都需要挂起,直到持有独占鎖的线程释放锁;乐观锁是先假定没有冲突直接进行操作如果因为有冲突而失败就重试,直到操作成功其中乐观锁用到的机制就是CAS,Compare and Swap
这样使用CAS就保证了原子操作。其余几个方法的原理跟这个相同在此不再过多的解释。
没看AtomicInteger 源码之前我认为其内部是用synchronized
来实现的原子操作。查阅资料后发现synchronized
会影响性能因为Java中的synchronized
锁是独占锁,虽然可以实现原子操作但是这种实现方式的并发性能很差。
总结一下AtomicInteger 中主偠实现了整型的原子操作,防止并发情况下出现异常结果其内部主要依靠JDK 中的unsafe 类操作内存中的数据来实现的。volatile 修饰符保证了value在内存中其怹线程可以看到其值得改变CAS操作保证了AtomicInteger 可以安全的修改value 的值。