【多线程】Java多线程基础(13)- 使用Atomic

454 阅读4分钟

Atomic(原子)

什么是Atomic

Atomic是Java中提供的一组原子类,可以实现对基本类型和对象类型的原子操作,它们常用于实现高并发的程序。

Atomic类提供了一些原子操作方法,如getsetcompareAndSet等,这些方法都是原子的,可以保证在多线程环境下的线程安全性和操作的可见性。

以下是几个常用的Atomic类:

  1. AtomicInteger:原子整型类,支持原子性的增加和减少操作。
  2. AtomicLong:原子长整型类,支持原子性的增加和减少操作。
  3. AtomicReference:原子引用类,支持原子性的读和写操作。
  4. AtomicBoolean:原子布尔型类,支持原子性的读和写操作。

为什么Atomic是线程安全的

Atomic 类提供了一组原子操作方法,这些方法可以保证在多线程环境下对数据的访问是线程安全的。Atomic 类之所以是线程安全的,是因为它内部使用了一些机制来保证对数据的原子性操作。

首先,Atomic 类中的一些方法使用了底层的 CPU 指令,例如 CAS(Compare-And-Swap)指令,来实现原子性操作。CAS 操作可以在一个步骤中读取一个内存位置的值,并将这个值与一个期望值进行比较,如果相等,则将一个新值写入该位置。这个操作是原子的,因为它在同一时刻只能被一个线程执行,其他线程需要等待该操作完成后才能进行下一步操作。

其次,Atomic 类中的一些方法使用了 volatile 关键字来保证数据的可见性。当一个变量被声明为 volatile 类型时,它的值将会被存储在主存中,而不是在线程的本地缓存中,这样所有的线程都可以读取到最新的值。这样就可以避免多个线程之间出现数据不一致的情况。

最后,Atomic 类中的一些方法使用了内部锁或者 synchronized 关键字来保证线程安全。当多个线程同时访问同一个 Atomic 对象时,这些方法会使用内部锁或 synchronized 关键字来确保同一时刻只有一个线程能够访问该对象,从而避免线程之间的竞争和冲突。

综上所述,Atomic 类之所以是线程安全的,是因为它内部使用了一些机制来保证对数据的原子性操作、可见性和线程安全。这些机制可以确保在多线程环境下,对数据的访问是正确、一致和可预期的。

什么时候使用Atomic

  1. 多线程环境下需要进行原子性操作的场景。例如,需要对计数器或状态标志进行原子性修改,或者需要对共享变量进行原子性读写等等。
  2. 无法使用锁或其他同步机制的场景。在某些情况下,锁或其他同步机制可能会带来过多的开销或死锁等问题,此时可以考虑使用 Atomic 类来实现原子性操作。
  3. 需要高效地实现某些算法或数据结构的场景。在某些算法或数据结构中,需要对某些变量或对象进行频繁的原子性操作,此时使用 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());
    }
}

具体的方法可以点击到类里面去查看