Atomic(原子)
什么是Atomic
Atomic是Java中提供的一组原子类,可以实现对基本类型和对象类型的原子操作,它们常用于实现高并发的程序。
Atomic类提供了一些原子操作方法,如get、set、compareAndSet等,这些方法都是原子的,可以保证在多线程环境下的线程安全性和操作的可见性。
以下是几个常用的Atomic类:
AtomicInteger:原子整型类,支持原子性的增加和减少操作。AtomicLong:原子长整型类,支持原子性的增加和减少操作。AtomicReference:原子引用类,支持原子性的读和写操作。AtomicBoolean:原子布尔型类,支持原子性的读和写操作。
为什么Atomic是线程安全的
Atomic 类提供了一组原子操作方法,这些方法可以保证在多线程环境下对数据的访问是线程安全的。Atomic 类之所以是线程安全的,是因为它内部使用了一些机制来保证对数据的原子性操作。
首先,Atomic 类中的一些方法使用了底层的 CPU 指令,例如 CAS(Compare-And-Swap)指令,来实现原子性操作。CAS 操作可以在一个步骤中读取一个内存位置的值,并将这个值与一个期望值进行比较,如果相等,则将一个新值写入该位置。这个操作是原子的,因为它在同一时刻只能被一个线程执行,其他线程需要等待该操作完成后才能进行下一步操作。
其次,Atomic 类中的一些方法使用了 volatile 关键字来保证数据的可见性。当一个变量被声明为 volatile 类型时,它的值将会被存储在主存中,而不是在线程的本地缓存中,这样所有的线程都可以读取到最新的值。这样就可以避免多个线程之间出现数据不一致的情况。
最后,Atomic 类中的一些方法使用了内部锁或者 synchronized 关键字来保证线程安全。当多个线程同时访问同一个 Atomic 对象时,这些方法会使用内部锁或 synchronized 关键字来确保同一时刻只有一个线程能够访问该对象,从而避免线程之间的竞争和冲突。
综上所述,Atomic 类之所以是线程安全的,是因为它内部使用了一些机制来保证对数据的原子性操作、可见性和线程安全。这些机制可以确保在多线程环境下,对数据的访问是正确、一致和可预期的。
什么时候使用Atomic
- 多线程环境下需要进行原子性操作的场景。例如,需要对计数器或状态标志进行原子性修改,或者需要对共享变量进行原子性读写等等。
- 无法使用锁或其他同步机制的场景。在某些情况下,锁或其他同步机制可能会带来过多的开销或死锁等问题,此时可以考虑使用
Atomic类来实现原子性操作。 - 需要高效地实现某些算法或数据结构的场景。在某些算法或数据结构中,需要对某些变量或对象进行频繁的原子性操作,此时使用
Atomic类可以提高程序的性能和效率。
在使用 Atomic 类时,尽管它提供了原子性操作,但是在同时进行多个原子操作时,仍然需要考虑同步问题,以确保程序的正确性。
虽然 Atomic 类内部使用了一些机制来保证对数据的原子性操作,但是它并没有提供对多个原子操作的原子性支持。当同时进行多个原子操作时,可能会出现数据竞争和冲突等问题,导致程序的行为不一致或者出现错误。
意思是多个原子操作还是需要考虑同步问题
例子
import java.util.concurrent.atomic.AtomicInteger;
class Counter {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
// 这里使用原子操作,使值加一。
count.incrementAndGet();
}
public int getCount() {
return count.get();
}
}
class Worker implements Runnable {
private Counter counter;
public Worker(Counter counter) {
this.counter = counter;
}
public void run() {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Worker(counter));
threads[i].start();
}
for (Thread thread : threads) {
thread.join();
}
System.out.println("Count: " + counter.getCount());
}
}
具体的方法可以点击到类里面去查看