目录
一、简介
java.util.concurrent.atomic
包提供了一些基于CAS(Compare-and-Swap)算法的原子操作类,用于在多线程环境下进行原子操作,避免了使用 synchronized
等锁机制的开销和复杂性。以下是该包中一些常用的类及其实现原理。
二、类详解
1. AtomicBoolean
AtomicBoolean
用于在多线程环境下对一个布尔类型的变量进行原子操作。它的实现原理是使用一个 volatile
修饰的 int
类型变量来表示布尔值,其中 1
表示 true
,0
表示 false
。它的操作方法包括 get()
、set()
、compareAndSet()
等。
public class AtomicBooleanDemo {
private static AtomicBoolean flag = new AtomicBoolean(false);
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
while (!flag.compareAndSet(false, true)) {
// do something
}
System.out.println("Thread 1 get the lock.");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag.set(false);
System.out.println("Thread 1 release the lock.");
});
Thread t2 = new Thread(() -> {
while (!flag.compareAndSet(false, true)) {
// do something
}
System.out.println("Thread 2 get the lock.");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag.set(false);
System.out.println("Thread 2 release the lock.");
});
t1.start();
t2.start();
t1.join();
t2.join();
}
}
2. AtomicInteger
AtomicInteger
用于在多线程环境下对一个整型变量进行原子操作。它的实现原理与 AtomicBoolean
类似,使用一个 volatile
修饰的 int
类型变量来表示整数值,同时使用 CAS 算法保证原子性。它的操作方法包括 get()
、set()
、getAndIncrement()
、compareAndSet()
等。
public class AtomicIntegerDemo {
private static AtomicInteger counter = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
counter.incrementAndGet();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
counter.incrementAndGet();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Counter: " + counter.get());
}
}
3. AtomicLong
AtomicLong
用于在多线程环境下对一个长整型变量进行原子操作。它的实现原理与 AtomicInteger
类似,使用一个 volatile
修饰的 long
类型变量来表示长整数值,同时使用 CAS 算法保证原子性。它的操作方法与 AtomicInteger
类似。
public class AtomicLongDemo {
private static AtomicLong counter = new AtomicLong(0L);
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000000; i++) {
counter.incrementAndGet();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000000; i++) {
counter.incrementAndGet();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Counter: " + counter.get());
}
}
4. AtomicReference
AtomicReference
用于在多线程环境下对一个对象类型的变量进行原子操作。它的实现原理是使用 volatile
修饰的 Object
类型变量来表示对象引用,同时使用 CAS 算法保证原子性。它的操作方法包括 get()
、set()
、compareAndSet()
等。
public class AtomicReferenceDemo {
private static AtomicReference<String> ref = new AtomicReference<>("Hello");
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
ref.compareAndSet("Hello", "World");
});
Thread t2 = new Thread(() -> {
ref.compareAndSet("Hello", "Java");
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Reference: " + ref.get());
}
}
5. AtomicStampedReference
AtomicStampedReference
通过维护一个时间戳(stamp)来解决ABA问题。在每次更新时,除了更新值以外还要更新时间戳。因此,即使值相同,时间戳也不同,从而避免了ABA问题。当然,这也要求每次更新时时间戳必须不同。
AtomicStampedReference<String> ref = new AtomicStampedReference<>("initial value", 0);
int currentStamp = ref.getStamp();
String currentValue = ref.getReference();
boolean success = ref.compareAndSet(currentValue, "new value", currentStamp, currentStamp + 1);
6. AtomicMarkableReference
AtomicMarkableReference
通过维护一个标记(mark)来解决ABA问题。在每次更新时,除了更新值以外还要更新标记。因此,即使值相同,标记也不同,从而避免了ABA问题。当然,这也要求每次更新时标记必须不同。
以下是 AtomicMarkableReference
的一个示例:
AtomicMarkableReference<String> ref = new AtomicMarkableReference<>("initial value", false);
boolean currentMark = ref.isMarked();
String currentValue = ref.getReference();
boolean success = ref.compareAndSet(currentValue, "new value", currentMark, !currentMark);
三、总结
java.util.concurrent.atomic
包提供了一些基于 CAS 算法的原子操作类,用于在多线程环境下进行原子操作。这些类的实现原理都是使用volatile
修饰的基本类型变量或对象引用变量,同时使用 CAS 算法保证原子性。在使用这些原子操作类时,需要注意它们的线程安全性和使用方式。