← 返回首页
⚛️

Java原子变量详解:AtomicInteger与CAS

📂 java ⏱ 4 min 610 words

Java原子变量详解:AtomicInteger与CAS

概述

原子变量是Java并发编程中的重要工具,它们提供了线程安全的操作,而无需使用锁。本教程介绍原子变量的使用和CAS(Compare-And-Swap)操作。

1. AtomicInteger

import java.util.concurrent.atomic.*;

public class AtomicIntegerExample {
    public static void main(String[] args) throws InterruptedException {
        AtomicInteger counter = new AtomicInteger(0);
        
        // 基本操作
        counter.set(10);
        System.out.println("当前值: " + counter.get());
        
        // 原子操作
        counter.incrementAndGet();  // ++i
        System.out.println("incrementAndGet: " + counter.get());
        
        counter.getAndIncrement();  // i++
        System.out.println("getAndIncrement: " + counter.get());
        
        counter.addAndGet(5);  // i += 5
        System.out.println("addAndGet: " + counter.get());
        
        // CAS操作
        boolean success = counter.compareAndSet(16, 100);
        System.out.println("CAS成功: " + success + ", 新值: " + counter.get());
        
        // 并发测试
        AtomicInteger atomicCounter = new AtomicInteger(0);
        int threadCount = 10;
        int incrementsPerThread = 10000;
        
        Thread[] threads = new Thread[threadCount];
        for (int i = 0; i < threadCount; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < incrementsPerThread; j++) {
                    atomicCounter.incrementAndGet();
                }
            });
            threads[i].start();
        }
        
        for (Thread thread : threads) {
            thread.join();
        }
        
        System.out.println("并发计数: " + atomicCounter.get());
        System.out.println("期望值: " + (threadCount * incrementsPerThread));
    }
}

2. AtomicReference

import java.util.concurrent.atomic.*;
import java.util.function.*;

public class AtomicReferenceExample {
    static class User {
        String name;
        int age;
        
        User(String name, int age) {
            this.name = name;
            this.age = age;
        }
        
        @Override
        public String toString() {
            return "User{name='" + name + "', age=" + age + "}";
        }
    }
    
    public static void main(String[] args) {
        AtomicReference<User> userRef = new AtomicReference<>(new User("Alice", 25));
        
        System.out.println("初始用户: " + userRef.get());
        
        // CAS更新
        User oldUser = userRef.get();
        User newUser = new User("Alice", 26);
        userRef.compareAndSet(oldUser, newUser);
        
        System.out.println("更新后: " + userRef.get());
        
        // updateAndGet
        userRef.updateAndGet(user -> {
            user.age++;
            return user;
        });
        
        System.out.println("updateAndGet: " + userRef.get());
        
        // getAndUpdate
        User previous = userRef.getAndUpdate(user -> {
            user.name = "Bob";
            return user;
        });
        
        System.out.println("前一个: " + previous);
        System.out.println("当前: " + userRef.get());
    }
}

3. AtomicStampedReference

import java.util.concurrent.atomic.*;

public class AtomicStampedReferenceExample {
    public static void main(String[] args) {
        AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(100, 0);
        
        // 获取值和版本号
        int[] stampHolder = new int[1];
        Integer value = ref.get(stampHolder);
        int stamp = stampHolder[0];
        
        System.out.println("值: " + value + ", 版本: " + stamp);
        
        // CAS更新(需要值和版本号都匹配)
        boolean success = ref.compareAndSet(100, 200, stamp, stamp + 1);
        System.out.println("CAS成功: " + success);
        
        value = ref.get(stampHolder);
        System.out.println("更新后: " + value + ", 版本: " + stampHolder[0]);
    }
}

4. 实际应用示例

线程安全的计数器

import java.util.concurrent.atomic.*;

public class ThreadSafeCounter {
    private final AtomicInteger count = new AtomicInteger(0);
    private final AtomicLong total = new AtomicLong(0);
    
    public int increment() {
        return count.incrementAndGet();
    }
    
    public int decrement() {
        return count.decrementAndGet();
    }
    
    public int get() {
        return count.get();
    }
    
    public void addToTotal(long value) {
        total.addAndGet(value);
    }
    
    public long getTotal() {
        return total.get();
    }
    
    public static void main(String[] args) throws InterruptedException {
        ThreadSafeCounter counter = new ThreadSafeCounter();
        
        Thread[] threads = new Thread[10];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    counter.increment();
                    counter.addToTotal(1);
                }
            });
            threads[i].start();
        }
        
        for (Thread thread : threads) {
            thread.join();
        }
        
        System.out.println("计数: " + counter.get());
        System.out.println("总计: " + counter.getTotal());
    }
}

线程安全的栈

import java.util.concurrent.atomic.*;

public class ConcurrentStack<E> {
    private final AtomicReference<Node<E>> top = new AtomicReference<>();
    
    private static class Node<E> {
        final E data;
        Node<E> next;
        
        Node(E data) {
            this.data = data;
        }
    }
    
    public void push(E data) {
        Node<E> newNode = new Node<>(data);
        Node<E> currentTop;
        
        do {
            currentTop = top.get();
            newNode.next = currentTop;
        } while (!top.compareAndSet(currentTop, newNode));
    }
    
    public E pop() {
        Node<E> currentTop;
        Node<E> newTop;
        
        do {
            currentTop = top.get();
            if (currentTop == null) {
                return null;
            }
            newTop = currentTop.next;
        } while (!top.compareAndSet(currentTop, newTop));
        
        return currentTop.data;
    }
    
    public static void main(String[] args) {
        ConcurrentStack<Integer> stack = new ConcurrentStack<>();
        
        // 压栈
        for (int i = 0; i < 10; i++) {
            stack.push(i);
        }
        
        // 弹栈
        Integer item;
        while ((item = stack.pop()) != null) {
            System.out.println("弹出: " + item);
        }
    }
}

5. 最佳实践

  1. 优先使用原子变量:比锁更轻量
  2. 使用CAS操作:原子更新操作
  3. 避免ABA问题:使用AtomicStampedReference
  4. 选择合适的类型:AtomicInteger、AtomicLong、AtomicReference等
  5. 注意性能:CAS在竞争激烈时性能下降

总结

原子变量是Java并发编程中的重要工具。掌握AtomicInteger、AtomicReference等的使用,可以编写高效的线程安全程序。在实际编程中,要根据需求选择合适的原子变量类型。