打开JUC包,看见的第一个就是atomic包,看下包结构:JAVA版本:1.8.0_172
我们简单的回顾一下原子性。
原子性
原子性是指:一个操作是不可中断的,要么全部执行成功,要么全部执行失败。在具体点,就是在多个线程一起执行的过程中,一个操作一旦开始,就不会被其他线程所干扰。以保证数据的准确性。
举几个常见的例子:
1. int a = 10;
2. a++;
3. int b=a;
4. a = a+1;
逐个分析:
- 将10 赋值给a;一步操作。
- 读取a的值;将a+1;将计算后的值赋值给a;三步操作。
- 读取a的值;将a的值赋值给b;两步操作。
- 同2;两步操作
所以只有1具备原子性。
多线程不加锁自增:
用实例来看下2:
static int count = 0;
@Test
public void thredInteger() throws InterruptedException {
// 打印10次
for (int j = 0; j < 10; j++) {
count = 0;
// 10个线程
for (int i = 0; i < 10; i++) {
new Thread() {
@Override
public void run() {
// 每个线程自增1000次
for(int k = 0; k < 1000; k++){
count++;
}
}
}.start();
}
Thread.sleep(1000);
System.out.println("count: " + count);
}
}
结果:可以看到有两条数据值出现问题。
那么我们要思考,如果保证数据的原子性呢,那既然是在多线程中出现的,我们用synchronized不就可以了。
好,我们试一下:
多线程使用synchronized自增:
@Test
public void synchronizedThredInteger() throws InterruptedException {
Object object = new Object();
// 打印10次
for (int j = 0; j < 10; j++) {
count = 0;
// 10个线程
for (int i = 0; i < 10; i++) {
new Thread() {
@Override
public void run() {
// 每个线程自增1000次
for (int k = 0; k < 1000; k++) {
synchronized (object){
count++;
}
}
}
}.start();
}
Thread.sleep(1000);
System.out.println("count: " + count);
}
}
结果:每次都是正确数据。
嘿,这TM不也可以么,为啥还要用Atomic包。
那么我们再来看下使用Atomic包下AtomicInteger类:
使用AtomicInteger
static AtomicInteger atomicInteger = new AtomicInteger(0);
@Test
public void atomicInteger() throws InterruptedException {
for (int j = 0; j < 10; j++) {
atomicInteger = new AtomicInteger(0);
for (int i = 0; i < 10; i++) {
new Thread() {
@Override
public void run() {
// 每个线程自增1000次
for (int k = 0; k < 1000; k++) {
atomicInteger.getAndIncrement();
}
}
}.start();
}
Thread.sleep(1000);
System.out.println("atomicInteger: " + atomicInteger);
}
}
结果:每次都是正确数据。
所以我们通过实例证明了AtomicInteger是可以保证数据原子性的。
AtomicInteger源码:
/**
* An {@code int} value that may be updated atomically. See the
* {@link java.util.concurrent.atomic} package specification for
* description of the properties of atomic variables. An
* {@code AtomicInteger} is used in applications such as atomically
* incremented counters, and cannot be used as a replacement for an
* {@link java.lang.Integer}. However, this class does extend
* {@code Number} to allow uniform access by tools and utilities that
* deal with numerically-based classes.
*
* @since 1.5
* @author Doug Lea
*/
/**
* 大意:
* 1.可以以原子方式更新。
* 2.用于原子递增计数器之类的应用操作,不能当做是Integer的替代品。
* 3.但是这个类确实扩展了Number.class,允许处理基于数值的类的工具和实用工具的统一访问。
*/
主代码:
// setup to use Unsafe.compareAndSwapInt for updates
// 使用Unsafe更新
private static final Unsafe unsafe = Unsafe.getUnsafe();
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
常用方法:
/**
* Atomically increments by one the current value.
* 递增当前一个当前值并保证原子性
* @return the previous value
* 返回原值
*/
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
/**
* Atomically increments by one the current value.
* 递增当前一个当前值并保证原子性
* @return the updated value
* 返回更新后的值
*/
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
/**
* Atomically decrements by one the current value.
*递减
* @return the updated value
*/
public final int decrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
}
/**
* Atomically decrements by one the current value.
* 递减
* @return the previous value
*/
public final int getAndDecrement() {
return unsafe.getAndAddInt(this, valueOffset, -1);
}
/**
* Atomically adds the given value to the current value.
* 将给定值添加到当前值并保证原子性
* @param delta the value to add
* @return the previous value
*/
public final int getAndAdd(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta);
}
/**
* Atomically adds the given value to the current value.
* 将给定值添加到当前值并保证原子性
* @param delta the value to add
* @return the updated value
*/
public final int addAndGet(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
}
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @param expect the expected value
* @param update the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
* 使用cas算法,更新数据
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}