一、原子性操作概念
所谓的原子性操作即不可中断,不可分割的操作,比如赋值操作:
原子性操作本身是线程安全的,但是 i++ 这个行为,事实上是 3 个原子性操作操作组成的:
| 12
 3
 4
 
 | 1、取 i 的值
 2、i + 1
 3、把新的值赋予 i
 
 | 
这三个步骤,每一步都是一个原子操作,但是合在一起,就不是原子操作,是线程不安全的。
换句话说,一个线程在步骤 1 取 i 的值结束后,还没有来得及进行步骤 2,另一个线程也可以取 i 的值了。
这也是分析同步问题产生的原因中的原理。
i++,i–,i = i + 1 这些都不是原子性操作。
只有int i = 1这个操作时原子性的
二、AtomicInteger
JDK 1.6 之后,Java 新增一个包java.util.concurrent.atomic,里面有各种原子类,比如:AtomicInteger 。
而 AtomicInteger 提供了各种自增,自减等方法,这些方法都是原子性的。
换句话说,自增方法 incrementAndGet 是线程安全的,同一个时间,只有一个线程可以调用这个方法。
代码实现:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | public class TestThread {public static void main(String[] args) {
 AtomicInteger atomicInteger = new AtomicInteger();
 final int i = atomicInteger.decrementAndGet();
 final int j = atomicInteger.incrementAndGet();
 final int k = atomicInteger.incrementAndGet();
 final int l = atomicInteger.addAndGet(3);
 System.out.println(i);
 System.out.println(j);
 System.out.println(k);
 System.out.println(l);
 }
 }
 
 
 -1
 0
 1
 4
 
 | 
三、同步测试
分别使用基本变量的非原子性操作符和原子性的 AtomicInteger 对象的 incrementAndGet 来进行多线程测试。
代码实现:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 
 | public class TestThread {
 private static int value = 0;
 private static AtomicInteger atomicValue = new AtomicInteger();
 
 public static void main(String[] args) {
 int number = 10000;
 Thread[] ts1 = new Thread[number];
 for (int i = 0; i < number; i++) {
 Thread t = new Thread(){
 @Override
 public void run() {
 value++;
 }
 };
 t.start();
 ts1[i] = t;
 }
 
 
 for (Thread t : ts1) {
 try {
 t.join();
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }
 
 System.out.printf("%d个线程进行value++后,value的值变成:%d%n", number,value);
 
 Thread[] ts2 = new Thread[number];
 for (int i = 0; i < number; i++) {
 Thread t = new Thread(){
 @Override
 public void run() {
 atomicValue.incrementAndGet();
 }
 };
 t.start();
 ts2[i] = t;
 }
 
 
 for (Thread t : ts2) {
 try {
 t.join();
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }
 System.out.printf("%d个线程进行atomicValue.incrementAndGet();后,atomicValue的值变成:%d%n", number,atomicValue.intValue());
 }
 }
 
 
 10000个线程进行value++后,value的值变成:9999
 10000个线程进行atomicValue.incrementAndGet();后,atomicValue的值变成:10000
 
 | 
四、使用 AtomicInteger 来替换 Hero 类中的 synchronized
Hero 类如下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 
 | public class Hero{public String name;
 public int hp;
 
 public int damage;
 public synchronized void recover(){
 hp=hp+1;
 }
 
 
 public void hurt(){
 
 synchronized (this) {
 hp=hp-1;
 }
 }
 
 public void attackHero(Hero h) {
 h.hp-=damage;
 System.out.format("%s 正在攻击 %s, %s的血变成了 %.0f%n",name,h.name,h.name,h.hp);
 if(h.isDead())
 System.out.println(h.name +"死了!");
 }
 
 public boolean isDead() {
 return 0>=hp?true:false;
 }
 }
 
 | 
接下来我们使用 AtomicInteger 对其进行替换:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | class Hero{public String name;
 public AtomicInteger hp = new AtomicInteger();
 
 public int damage;
 public synchronized void recover(){
 hp.incrementAndGet();
 }
 
 public void hurt(){
 hp.decrementAndGet();
 }
 
 public void attackHero(Hero h) {
 h.hp.addAndGet(0 - damage);
 System.out.format("%s 正在攻击 %s, %s的血变成了 %.0f%n",name,h.name,h.name,h.hp);
 if(h.isDead())
 System.out.println(h.name +"死了!");
 }
 
 public boolean isDead() {
 return 0>=hp.intValue()?true:false;
 }
 }
 
 | 
五、总结
本篇文章我们介绍了原子性操作的概念,以及原子性操作的类:AtomicInteger。并进行了同步测试以及对 Hero 类进行了替换
好了,本篇文章到这里就结束了,感谢你的阅读🤝