如何解决线程安全问题(不涉及分布式情况)

线程安全问题本质

当多个线程并发操作共享资源(变量/对象)时,可能因非原子性操作或内存可见性问题导致数据不一致。


解决方案一:synchronized 关键字

实现方式:

  1. 实例方法同步锁
    在实现Runnable接口的自定义线程类中,对操作共享资源的代码块使用同步锁:

    public void run() {
        synchronized(this) { // 锁住当前实例对象
            // 操作共享资源的代码
        }
    }
    
  2. 静态资源同步锁
    若操作静态变量,需使用类级别的锁:

    synchronized(MyThread.class) { // 锁住类的Class对象
        // 操作静态变量的代码
    }
    

注意事项:

  • 同步范围应尽量缩小(锁粒度最小化)以提高并发效率
  • 避免在构造方法中使用同步(可能导致对象未完全初始化)

解决方案二:Lock 显式锁

实现步骤:

  1. 创建ReentrantLock实例(推荐成员变量)

    private final Lock lock = new ReentrantLock();
    
  2. 显式加锁与释放(必须保证释放)

    public void run() {
        lock.lock();  // 手动加锁
        try {
            // 操作共享资源的代码
        } finally {
            lock.unlock(); // 必须放在finally块确保释放
        }
    }
    

优势:

  • 支持可中断锁(lockInterruptibly()
  • 支持超时获取锁(tryLock(long, TimeUnit)
  • 支持公平锁策略(构造函数传true

最佳实践建议

  1. 优先使用synchronized
    简单场景下更安全(自动释放锁),JVM会优化锁升级(偏向锁->轻量级锁->重量级锁)

  2. 需要精细控制时选择Lock
    当需要以下特性时:

    • 尝试获取锁(tryLock)
    • 等待锁可中断
    • 需要公平锁机制
    • 需要绑定多个Condition
  3. 性能考量
    JDK1.6+版本中两者性能差异不大,应优先考虑代码可维护性

  4. 避免嵌套锁
    防止死锁,加锁顺序需全局统一

你可能感兴趣的:(java)