当前位置: 首页 > news >正文

线程同步机制


知识点详细说明

线程同步机制是解决多线程环境下资源竞争和数据不一致问题的核心手段。以下是Java中常用的线程同步方式及其原理、适用场景和注意事项:


1. synchronized关键字

原理
  • 锁机制:基于对象监视器(Monitor),同一时刻只有一个线程能持有锁。

  • 锁对象

    • 实例方法:锁对象为当前实例(this)。
    • 静态方法:锁对象为类的Class对象。
    • 同步代码块:锁对象由用户指定(如Object lock)。
  • 注意:线程同步的本质是:线程排队执行就是同步机制。

  • 语法格式 :
    synchronized(必须是需要排队的这几个线程共享的对象){
    //需要同步的代码
    }

示例
// 实例方法同步
public synchronized void add() {count++;
}// 静态方法同步
public static synchronized void staticAdd() {staticCount++;
}// 同步代码块
public void blockAdd() {synchronized (lockObject) {count++;}
}
优点与缺点
优点缺点
语法简单,自动释放锁。功能单一(不可中断、不支持超时)。
无需手动管理锁的获取与释放。锁粒度粗时性能较差。
适用场景
  • 简单的代码块同步,如单方法内的共享资源保护。

2. ReentrantLock显式锁

原理
  • 可重入锁:允许同一线程多次获取同一把锁。
  • 高级功能:支持公平锁、可中断锁、超时尝试获取锁、条件变量(Condition)。
示例
private final ReentrantLock lock = new ReentrantLock();public void add() {lock.lock();try {count++;} finally {lock.unlock();}
}
优点与缺点
优点缺点
支持灵活的锁控制(如超时)。需手动释放锁,易遗漏导致死锁。
可配合Condition实现精准唤醒。代码复杂度较高。
适用场景
  • 需要复杂锁逻辑的场景,如限时等待、条件分支唤醒。

3. volatile关键字

原理
  • 可见性:强制线程从主内存读取变量,修改后立即写回主内存。
  • 禁止指令重排序:通过内存屏障(Memory Barrier)保证代码执行顺序。
示例
private volatile boolean flag = false;public void setFlag() {flag = true; // 对其他线程立即可见
}
优点与缺点
优点缺点
轻量级,无锁竞争。仅保证可见性,不保证原子性。
适合单写多读场景。无法解决复合操作(如i++)的线程安全。
适用场景
  • 状态标志位(如开关控制),单例模式的双重检查锁。

4. 原子类(AtomicInteger等)

原理
  • CAS操作:通过CPU指令(Compare-And-Swap)实现无锁原子操作。
示例
private AtomicInteger count = new AtomicInteger(0);public void add() {count.incrementAndGet();
}
优点与缺点
优点缺点
高性能(无锁竞争)。仅适用于单一变量的简单操作。
无需显式同步。无法处理复杂逻辑的原子性。
适用场景
  • 计数器、状态标记等简单原子操作。

5. 线程同步工具类

(1) CountDownLatch
  • 原理:通过计数器等待多个线程完成。
  • 示例:主线程等待所有子线程完成:
    CountDownLatch latch = new CountDownLatch(3);
    // 子线程中
    latch.countDown();
    // 主线程中
    latch.await();
    
(2) CyclicBarrier
  • 原理:线程到达屏障点后等待其他线程,全部到达后继续执行。
  • 示例:多阶段任务协同:
    CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("所有线程到达屏障"));
    // 线程中
    barrier.await();
    
(3) Semaphore
  • 原理:控制同时访问资源的线程数量。
  • 示例:限制数据库连接池并发数:
    Semaphore semaphore = new Semaphore(10);
    semaphore.acquire(); // 获取许可
    semaphore.release(); // 释放许可
    

6. 线程封闭(ThreadLocal

原理
  • 线程本地存储:每个线程拥有独立的变量副本,避免共享。
  • 示例:保存用户会话信息:
    private static ThreadLocal<User> userHolder = new ThreadLocal<>();
    userHolder.set(currentUser); // 当前线程存储
    User user = userHolder.get(); // 当前线程获取
    
优点与缺点
优点缺点
彻底避免线程安全问题。可能引发内存泄漏(需及时清理)。
适合线程间数据隔离的场景。不适用于跨线程数据共享。

同步机制对比总结

机制锁类型性能适用场景
synchronized悲观锁中等简单同步块或方法
ReentrantLock悲观锁中高复杂锁逻辑(超时、条件变量)
volatile无锁(可见性)状态标志位
原子类无锁(CAS)极高计数器、简单变量更新
工具类依赖具体实现可变多线程协同(如计数等待、限流)
ThreadLocal无锁(线程封闭)线程隔离数据(如数据库连接)

记忆方法

  • 口诀
    同步锁,原子类,volatile保可见;工具协同ThreadLocal,各司其职解难题。
  • 对比记忆
    • synchronized像公共电话亭(一次一人使用)。
    • ReentrantLock像智能门锁(可设置密码、超时)。
    • ThreadLocal像个人储物柜(各自独立,互不干扰)。

最佳实践

  1. 优先使用无锁方案:如原子类、ThreadLocal
  2. 减小锁粒度:同步代码块 > 同步方法,锁对象分离(如细粒度锁)。
  3. 避免锁嵌套:预防死锁,按固定顺序获取锁。
  4. 及时释放资源ReentrantLock需在finally中解锁,ThreadLocal使用后调用remove()

相关文章:

  • FlashInfer - 测试的GPU H100 SXM、A100 PCIe、RTX 6000 Ada、RTX 4090
  • Docker 介绍与使用
  • Mysql 存储引擎
  • 系统漏洞扫描服务:维护网络安全的关键与服务原理?
  • 打卡DAY25
  • [Vue3]语法变动
  • 企业报表平台如何实现降本增效
  • 数字信号处理-大实验1.3
  • vue中,created和mounted两个钩子之间调用时差值受什么影响
  • 静电的起因与静电效应:技术分析与应用
  • SVG 知识详解:从入门到精通
  • 如何远程执行脚本不留痕迹
  • 3DMAX脚本病毒Spy CA查杀方法
  • TypeScript泛型:从入门到精通的全方位指南
  • 软考软件设计师中级——软件工程笔记
  • 通用软件项目技术报告 - 术语词典
  • YashanDB V23.4 LTS 正式发布|两地三中心、库级闪回重磅特性上线,生产级可用性再升级
  • 流速仪数据处理及流量断面线绘制
  • CS4334:一款高性能的立体声音频数模转换器
  • Linux操作系统实战:中断源码的性能分析(转)
  • 特朗普促卡塔尔说服伊朗放弃核计划,伊朗总统:你来吓唬我们?
  • KPL“王朝”诞生背后:AG和联赛一起迈向成熟
  • 来沪一个月几乎未花住宿钱,女子虚构卫生问题屡薅酒店羊毛被刑拘
  • 耗资10亿潮汕豪宅“英之园”将强拆?区政府:非法占用集体土地
  • 反制美国钢铝关税!印度拟对美国部分商品征收关税
  • 英国收紧移民政策,技术工作签证、大学招生面临更严要求