什么是原子性操作
一个操作或者多个操作或者全部执行并且执行的过程不会被任何因素打断,或者就都不执行。A
想要从自己的账户中转1000块钱到B的账户里。那个从A开始转帐,到转帐结束这个过程,命名一个事务。在这个事务里,执行以下操作:
- 从A的账户中减去1000块钱。如果A的账户原来有3000块钱,现在就变成2000块钱了。
- 在B的账户里加了1000块钱。如果B的账户如果本来有2000块钱,现在就变成了3000块钱了。如果在A的账户已经减掉了1000块钱的时候,突然发生了意外,比如块停电什么的,导致转帐事务意外终止了,而此时B的账户里还没有增加1000块钱。现在,我们称这个操作失败了,要进行回滚。回滚就是回到事务开始之前的状态,否则回到A的账户还没有减1000块的状态,B的账户成功的原来的状态。此时A的账户仍然有3000块,B的账户仍然有2000块。 通俗点成功讲:操作要一起、要失败大家一起失败
如何把非原子性操作变成原子性
- volatile 关键字保证连续性,不一定保证原子性
- 同步关机字,使操作具有原子性
package com.xdclass.safe;
import java.util.concurrent.CountDownLatch;
/**
* 线程不安全操作代码实例
*/
public class UnSafeThread {
private static int num = 0;
private static CountDownLatch countDownLatch = new CountDownLatch(10);
/**
* 每次调用对num进行++操作,加上synchronized使得num++操作变成原子操作
*/
public static synchronized void inCreate() {
num++;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
for (int j = 0; j < 100; j++) {
inCreate();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//每个线程执行完成之后,调用countDownLatch
countDownLatch.countDown();
}).start();
}
while (true) {
if (countDownLatch.getCount() == 0) {
System.out.println(num);
break;
}
}
}
}