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

线程同步机制


知识点详细说明

线程同步机制是解决多线程环境下资源竞争和数据不一致问题的核心手段。以下是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()
http://www.xdnf.cn/news/6252.html

相关文章:

  • GO 小游戏在线试水
  • UE中:puerts使用指南(持续更新)
  • 服务器时间发生跳变导致hghac中对应主机状态频繁切换为crash或stop
  • 从Transformer到多模态智能,剖析人工智能时代的核心引擎​​
  • Linux服务之lvs集群与dr模式部署
  • Xsens发布专为生物力学打造的全新人体模型
  • centos6.10在Macbook m芯片上使用
  • Android 设置系统默认通话应用,打不开通话界面
  • VSCode python配置
  • 数据结构第七章(二)-树形查找:二叉排序树与平衡二叉树
  • Virtualized Table 虚拟化表格 el-table-v2 表头分组 多级表头的简单示例
  • 编程的本质, 就是创造工具
  • 【网工第6版】第10章 网络规划和设计②
  • Linux 中 open 函数的本质与细节全解析
  • 【爬虫】DrissionPage-2
  • 《低代码AI革命:技术平权的曙光还是数字封建的陷阱?》
  • 鸿蒙OSUniApp 制作动态加载的瀑布流布局#三方框架 #Uniapp
  • 2025 年主流 Java 框架解析与实践:构建高性能 Web 应用
  • Go语言八股之Mysql基础详解
  • 刷题记录(4)数组元素相关操作
  • 【网络实验】-BGP-EBGP的基本配置
  • 【CTFShow】Web入门-信息搜集
  • Python 接入DeepSeek
  • Redis持久化存储
  • 软件测试--入门
  • unity 鼠标更换指定图标
  • MongoDB 的核心概念(文档、集合、数据库、BSON)是什么?
  • 如何选择合适的企业级商城系统前端状态管理方案?
  • 【NLP 困惑度解析和python实现】
  • 并查集原理及实现:路径压缩,按秩合并