文章目录
- 1 CAS
- 1.1 是什么
- 1.2 原理
- 1.3 UnSafe
- 1.4 自旋锁
- 1.5 CAS的问题
- 1.5.1 死循环消耗CPU资源
- 1.5.2 ABA问题
- 2 原子操作类
- 2.1 引用类型原子类
- 2.1.1 AtomicReference
- 2.1.2 AtomicStampedReference
- 2.1.3 AtomicMarkableReference
- 2.2 基本类型原子类
- 2.3 数组类型原子类
- 2.4 对象的属性修改原子类
- 2.4.1 使用目的
- 2.4.2 使用要求
- 2.4.3 AtomicIntegerFieldUpdater使用Demo
- 2.4.4 AtomicReferenceFieldUpdater使用Demo
1 CAS
1.1 是什么
1.2 原理
1.3 UnSafe
1.4 自旋锁
1.5 CAS的问题
1.5.1 死循环消耗CPU资源
1.5.2 ABA问题
很形象的两个例子:
- 隔壁老王动了你GF,但是又回复了原样。你能认为这件事情没有发生过么?
- 挪用公款然后抹平了亏空。
【问题解决】
版本号和戳记流水机制。
2 原子操作类
2.1 引用类型原子类
2.1.1 AtomicReference
AtomicReference<Phone> atomicPhone = new AtomicReference<>();
2.1.2 AtomicStampedReference
2.1.3 AtomicMarkableReference
2.2 基本类型原子类
通过一个demo来了解AtomicInteger的使用。
package org.example.atomicnum;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
class Number {
AtomicInteger number = new AtomicInteger();
public void increment() {
number.getAndIncrement();
}
}
public class Demo {
private static int SIZE = 50;
private static Number myNumber = new Number();
private static CountDownLatch countDownLatch = new CountDownLatch(SIZE);
public static void main(String[] args) {
for (int i = 0; i < SIZE; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
for (int j = 1; j <= 1000; j++) {
myNumber.increment();
}
} finally {
countDownLatch.countDown();
}
}
}, String.valueOf(i)).start();
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 如果没有使用CountDownLatch,很可能main thread查早了,查出来的结果不对。
System.out.println("main thread: the result = " + myNumber.number.get());
}
}
2.3 数组类型原子类
2.4 对象的属性修改原子类
2.4.1 使用目的
以一种线程安全的方式操作非线程安全对象内的某些字段。
2.4.2 使用要求
- 更新的对象属性必须使用public volatile进行修饰
- 因为属性修改原子类都是抽象类,所以必须使用静态方法newUpdater()来创建更新器实例,并且设置想要更新的类和属性。
2.4.3 AtomicIntegerFieldUpdater使用Demo
package org.example.atomicfieldupdater;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
public class BankAccount {
String bankName = "CCB";
public volatile int money = 0;
private static AtomicIntegerFieldUpdater moneyUpdater =
AtomicIntegerFieldUpdater.newUpdater(BankAccount.class, "money");
/**
* 局部微创小手术
*
* @param bankAccount
*/
public static void transfer(BankAccount bankAccount) {
moneyUpdater.getAndIncrement(bankAccount);
}
}
package org.example.atomicfieldupdater;
import java.util.concurrent.CountDownLatch;
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(10);
BankAccount bankAccount = new BankAccount();
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
for (int j = 0; j < 1000; j++) {
BankAccount.transfer(bankAccount);
}
} finally {
countDownLatch.countDown();
}
}
}).start();
}
countDownLatch.await();
System.out.println("money = " + bankAccount.money);
}
}
2.4.4 AtomicReferenceFieldUpdater使用Demo
package org.example.atomicfieldupdater;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
class MyVar {
public volatile Boolean isInit = Boolean.FALSE;
private static AtomicReferenceFieldUpdater<MyVar, Boolean> initUpdater =
AtomicReferenceFieldUpdater.newUpdater(MyVar.class, Boolean.class, "isInit");
public static void init(MyVar myVar) {
if (initUpdater.compareAndSet(myVar, Boolean.FALSE, Boolean.TRUE)) {
System.out.println(Thread.currentThread().getName() + "\t" + "start init, need 2 seconds.");
sleepSeconds(2);
System.out.println(Thread.currentThread().getName() + "\t" + "init over.");
} else {
System.out.println(Thread.currentThread().getName() + "\t" + "Other thread executing init work.");
}
}
private static void sleepSeconds(int seconds) {
try {
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public class Demo2 {
public static void main(String[] args) {
MyVar myVar = new MyVar();
for (int i = 1; i <= 5; i++) {
new Thread(() -> {
MyVar.init(myVar);
}, String.valueOf(i)).start();
}
}
}