Java线程安全流程规整

wen java案例 29

本文目录导读:

Java线程安全流程规整

  1. 线程安全核心概念
  2. 线程安全实现方式(6大策略)
  3. 线程安全设计原则
  4. 线程安全的正确实践
  5. 性能优化建议
  6. 常见线程安全问题排查
  7. 最佳实践总结

我来系统地整理Java线程安全的完整知识体系。

线程安全核心概念

1 什么是线程安全

当多个线程访问某个类时,这个类始终表现出正确的行为,就称这个类是线程安全的。

2 线程不安全的根本原因

// 根本原因:多线程操作共享数据
private int count = 0;
public void increment() {
    count++;  // 不是原子操作:读取-修改-写入
}

三个条件同时发生时必然出现线程安全问题:

  • 多线程环境
  • 共享资源
  • 非原子操作

线程安全实现方式(6大策略)

1 同步机制(Synchronized)

// 1. 同步方法
public synchronized void safeMethod() {
    // 线程安全操作
}
// 2. 同步代码块(推荐:粒度更细)
public void safeBlock() {
    synchronized(this) {
        // 需要同步的操作
    }
}
// 3. 静态方法同步(类锁)
public static synchronized void staticSafeMethod() {
    // 同步操作
}
// 4. 指定对象锁
private final Object lock = new Object();
public void customLock() {
    synchronized(lock) {
        // 同步操作
    }
}

2 Lock锁机制

import java.util.concurrent.locks.*;
public class LockExample {
    private final ReentrantLock lock = new ReentrantLock();
    private int count = 0;
    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();  // 必须释放锁
        }
    }
    // 尝试获取锁
    public boolean tryIncrement() {
        if (lock.tryLock()) {
            try {
                count++;
                return true;
            } finally {
                lock.unlock();
            }
        }
        return false;
    }
    // 读写锁
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private Map<String, String> cache = new HashMap<>();
    public String get(String key) {
        rwLock.readLock().lock();
        try {
            return cache.get(key);
        } finally {
            rwLock.readLock().unlock();
        }
    }
    public void put(String key, String value) {
        rwLock.writeLock().lock();
        try {
            cache.put(key, value);
        } finally {
            rwLock.writeLock().unlock();
        }
    }
}

3 Volatile关键字

public class VolatileExample {
    // volatile保证可见性和禁止指令重排
    private volatile boolean flag = false;
    private volatile int count = 0;
    public void writer() {
        count = 10;      // 普通写
        flag = true;     // volatile写,保证前面的写操作对其他线程可见
    }
    public void reader() {
        if (flag) {      // volatile读
            System.out.println(count);  // 一定能看到10
        }
    }
}

4 原子类(Atomic)

import java.util.concurrent.atomic.*;
public class AtomicExample {
    private AtomicInteger count = new AtomicInteger(0);
    private AtomicLong longValue = new AtomicLong(0L);
    private AtomicBoolean flag = new AtomicBoolean(false);
    private AtomicReference<String> ref = new AtomicReference<>("initial");
    public void increment() {
        count.incrementAndGet();    // 原子自增
        count.addAndGet(10);        // 原子增加
        count.compareAndSet(5, 6);  // CAS操作
    }
    // 复杂对象原子更新
    private AtomicReference<User> userRef = new AtomicReference<>();
    // 字段原子更新
    private AtomicIntegerFieldUpdater<Counter> updater = 
        AtomicIntegerFieldUpdater.newUpdater(Counter.class, "count");
}

5 并发容器

import java.util.concurrent.*;
public class ConcurrentCollectionExample {
    // 1. ConcurrentHashMap - 分段锁
    private ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
    // 2. CopyOnWriteArrayList - 写时复制
    private CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
    // 3. BlockingQueue - 阻塞队列
    private BlockingQueue<String> queue = new LinkedBlockingQueue<>(100);
    // 4. ConcurrentLinkedQueue - 无锁队列
    private ConcurrentLinkedQueue<String> concurrentQueue = new ConcurrentLinkedQueue<>();
    public void safeOperations() {
        // ConcurrentHashMap原子操作
        map.putIfAbsent("key", "value");     // 不存在才put
        map.computeIfAbsent("key", k -> "new");  // 不存在才计算
        map.replace("key", "old", "new");    // 替换操作
        // BlockingQueue阻塞操作
        try {
            queue.put("item");           // 满时阻塞
            String item = queue.take();  // 空时阻塞
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

6 ThreadLocal

public class ThreadLocalExample {
    // 每个线程维护自己的变量副本
    private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
        @Override
        protected Integer initialValue() {
            return 0;  // 初始值
        }
    };
    // Java 8 简化写法
    private static ThreadLocal<SimpleDateFormat> dateFormat = 
        ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
    // 使用示例
    public void process() {
        Integer value = threadLocal.get();  // 获取当前线程的变量
        threadLocal.set(value + 1);         // 设置当前线程的变量
        threadLocal.remove();               // 使用后清理(避免内存泄漏)
    }
    // 实际应用:数据库连接管理
    private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() {
        @Override
        protected Connection initialValue() {
            return DriverManager.getConnection(DB_URL);
        }
    };
    public static Connection getConnection() {
        return connectionHolder.get();
    }
}

线程安全设计原则

1 不变性(Immutability)

// 不可变对象天然线程安全
public final class ImmutableObject {
    private final int id;
    private final String name;
    private final List<String> tags;  // 防御性拷贝
    public ImmutableObject(int id, String name, List<String> tags) {
        this.id = id;
        this.name = name;
        this.tags = Collections.unmodifiableList(new ArrayList<>(tags));
    }
    public int getId() { return id; }
    public String getName() { return name; }
    public List<String> getTags() {
        return tags;  // 返回不可修改的视图
    }
}

2 线程封闭

// 栈封闭:变量在方法内部,不会被共享
public void stackConfined() {
    int localVar = 0;  // 每个线程有自己的栈帧
    for (int i = 0; i < 100; i++) {
        localVar++;
    }
}
// ThreadLocal封闭:每个线程自己的副本
private static ThreadLocal<TransactionManager> txManager = new ThreadLocal<>();

3 实例封闭

public class InstanceConfinement {
    private final Set<String> set = new HashSet<>();  // 私有成员
    private final Object lock = new Object();
    public void add(String item) {
        synchronized(lock) {  // 通过锁保护
            set.add(item);
        }
    }
    public boolean contains(String item) {
        synchronized(lock) {
            return set.contains(item);
        }
    }
}

线程安全的正确实践

1 类级别线程安全

public class ThreadSafeCounter {
    private final AtomicInteger count = new AtomicInteger(0);
    private volatile boolean initialized = false;
    // 线程安全的初始化
    public void init() {
        if (!initialized) {
            synchronized(this) {
                if (!initialized) {
                    // 双重检查锁定
                    doInit();
                    initialized = true;
                }
            }
        }
    }
    // 线程安全的方法
    public int incrementAndGet() {
        return count.incrementAndGet();
    }
    // 复合操作需要同步
    public int getAndReset() {
        // 保证获取和重置的原子性
        synchronized(this) {
            int current = count.get();
            count.set(0);
            return current;
        }
    }
    private void doInit() {
        // 初始化代码
    }
}

2 发布对象的安全

public class SafePublication {
    // 1. 安全发布方式
    private static volatile Singleton instance;  // volatile确保可见性
    // 2. 通过工厂方法安全发布
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized(SafePublication.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
    // 3. 通过静态初始化安全发布(推荐)
    private static class LazyHolder {
        static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance2() {
        return LazyHolder.INSTANCE;
    }
}

性能优化建议

1 锁优化策略

public class LockOptimization {
    // 1. 减少锁持有时间
    public void process(List<String> items) {
        // 只对必要部分加锁
        String result = expensiveComputation(items.get(0));
        synchronized(this) {
            updateSharedState(result);
        }
    }
    // 2. 减小锁粒度
    private final Object lock1 = new Object();
    private final Object lock2 = new Object();
    private Map<String, String> map1 = new HashMap<>();
    private Map<String, String> map2 = new HashMap<>();
    public void updateMap1(String key, String value) {
        synchronized(lock1) {
            map1.put(key, value);
        }
    }
    public void updateMap2(String key, String value) {
        synchronized(lock2) {
            map2.put(key, value);
        }
    }
    // 3. 锁分离(读写锁)
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    // 4. 锁粗化(避免频繁加解锁)
    public void coarsenLock() {
        synchronized(this) {
            // 多个操作合并
            doOperation1();
            doOperation2();
            doOperation3();
        }
    }
}

2 选择合适的工具

public class ToolSelection {
    // 场景1: 计数器 → 使用AtomicInteger
    private final AtomicInteger counter = new AtomicInteger(0);
    // 场景2: 共享变量标志位 → 使用volatile
    private volatile boolean running = true;
    // 场景3: 复杂状态 → 使用Lock或synchronized
    private final ReentrantLock lock = new ReentrantLock();
    private int state1, state2, state3;
    // 场景4: 缓存 → 使用ConcurrentHashMap
    private final ConcurrentHashMap<String, CacheEntry> cache = 
        new ConcurrentHashMap<>();
    // 场景5: 生产者消费者 → 使用BlockingQueue
    private final BlockingQueue<Task> taskQueue = 
        new ArrayBlockingQueue<>(1000);
    // 场景6: 每个线程独立数据 → 使用ThreadLocal
    private final ThreadLocal<UserContext> userContext = 
        ThreadLocal.withInitial(UserContext::new);
}

常见线程安全问题排查

1 典型问题模式

// 问题1: 非原子检查后执行
public class CheckThenAct {
    private Vector<String> vector = new Vector<>();
    // 问题代码
    public void wrongMethod(String item) {
        if (!vector.contains(item)) {  // 检查
            vector.add(item);          // 执行(可能被其他线程干扰)
        }
    }
    // 正确代码
    public synchronized void correctMethod(String item) {
        if (!vector.contains(item)) {
            vector.add(item);
        }
    }
}
// 问题2: 发布逸出
public class EscapeExample {
    private final Map<String, String> map;
    // 问题代码:this引用逸出
    public EscapeExample() {
        // 不应该在构造器中发布this
        GlobalRegistry.register(this);  // ❌
        map = new HashMap<>();
    }
    // 正确做法:使用工厂方法
    private EscapeExample(Map<String, String> map) {
        this.map = map;
    }
    public static EscapeExample create() {
        EscapeExample instance = new EscapeExample(new HashMap<>());
        GlobalRegistry.register(instance);  // ✅ 构造完成后注册
        return instance;
    }
}
// 问题3: 隐藏的迭代器
public class HiddenIterator {
    private final Set<Integer> set = new HashSet<>();
    // 问题代码:toString()隐藏了迭代
    public String wrongToString() {
        return set.toString();  // ❌ 内部迭代,如果在迭代中修改会抛异常
    }
    // 正确代码
    public synchronized String correctToString() {
        return set.toString();
    }
}

2 调试工具

// 1. 线程转储分析(Jstack)
jstack <pid> > thread_dump.txt
// 2. JVM参数检测
-XX:+UnlockDiagnosticVMOptions 
-XX:+PrintConcurrentLocks
// 3. 代码检测
public class DeadlockDetector {
    public static void detectDeadlock() {
        ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
        long[] threadIds = threadBean.findDeadlockedThreads();
        if (threadIds != null) {
            System.out.println("Deadlock detected!");
            for (long id : threadIds) {
                ThreadInfo info = threadBean.getThreadInfo(id);
                System.out.println("Thread: " + info.getThreadName());
            }
        }
    }
}

最佳实践总结

1 线程安全等级

等级 描述 示例
不可变 对象创建后不能修改 String, Integer
绝对线程安全 任何环境都安全 ConcurrentHashMap
相对线程安全 单操作安全,复合操作需同步 Vector, Hashtable
线程兼容 通过外部同步实现安全 ArrayList, HashMap
线程对立 即使外部同步也不安全 (极少见)

2 选择策略决策树

是否需要共享数据?
├── 否 → 使用ThreadLocal或栈封闭
└── 是 → 数据是否可变?
    ├── 否 → 使用不可变对象
    └── 是 → 是否需要原子性?
        ├── 否 → 使用volatile
        └── 是 → 操作是否简单?
            ├── 是 → 使用Atomic类
            └── 否 → 是否需要读多写少?
                ├── 是 → 使用ReadWriteLock
                └── 否 → 使用synchronized或ReentrantLock

3 编码规范

/**
 * 线程安全检查清单:
 * 
 * [ ] 所有共享变量是否被正确保护?
 * [ ] 复合操作是否原子化?
 * [ ] 是否存在竞态条件?
 * [ ] 是否存在可见性问题?
 * [ ] 是否存在线程封闭的需求?
 * [ ] 是否选择了合适的同步策略?
 * [ ] 是否存在死锁风险?
 * [ ] 锁的粒度是否合适?
 */

这种系统化的线程安全处理方式,能够帮助你在多线程编程中做出正确的决策,避免常见的并发问题。

抱歉,评论功能暂时关闭!