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

线程锁和线程同步

 线程锁和线程同步

线程锁的概念

线程锁是一种用于控制多个线程对共享资源访问的机制,目的是确保在同一时刻,只有一个线程能够访问共享资源,避免出现数据不一致、竞态条件等问题。就像在生活中,一把钥匙对应一扇门,同一时间只有拿到钥匙的人能进入门内。

synchronized关键字

synchronized是 Java 内置的用于实现线程同步的关键字,它可以应用在以下几个方面:

1. 修饰实例方法

synchronized修饰一个实例方法时,锁对象是当前对象(this)。这意味着在同一时刻,只有一个线程能够进入该实例方法进行操作。

class Counter {private int count = 0;// 修饰实例方法,锁对象是当前Counter实例public synchronized void increment() {count++;}public int getCount() {return count;}
}public class Main1 {public static void main(String[] args) {Counter counter = new Counter();Thread thread1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {counter.increment();}});Thread thread2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {counter.increment();}});thread1.start();thread2.start();try {thread1.join();thread2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("最终计数: " + counter.getCount());}
}

修饰静态方法

synchronized修饰静态方法时,锁对象是该类的Class对象,因为静态方法属于类,所有该类的实例共享同一个Class对象锁。

class StaticCounter {private static int count = 0;// 修饰静态方法,锁对象是StaticCounter类的Class对象public static synchronized void increment() {count++;}public static int getCount() {return count;}
}public class Main2 {public static void main(String[] args) {Thread thread1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {StaticCounter.increment();}});Thread thread2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {StaticCounter.increment();}});thread1.start();thread2.start();try {thread1.join();thread2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("最终计数: " + StaticCounter.getCount());}
}

修饰代码块

可以使用synchronized关键字修饰代码块,显式指定锁对象。这比修饰方法更加灵活,可以只对关键代码部分进行同步,提高程序性能。

class BankAccount {private int balance = 1000;public void transfer(BankAccount other, int amount) {// 这里使用this和other作为锁对象,保证转账操作的原子性synchronized (this) {synchronized (other) {if (this.balance >= amount) {this.balance -= amount;other.balance += amount;}}}}public int getBalance() {return balance;}
}public class Main3 {public static void main(String[] args) {BankAccount account1 = new BankAccount();BankAccount account2 = new BankAccount();Thread thread = new Thread(() -> {account1.transfer(account2, 500);});thread.start();try {thread.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("account1余额: " + account1.getBalance());System.out.println("account2余额: " + account2.getBalance());}
}

synchronized的工作原理

当一个线程访问被synchronized修饰的方法或代码块时:

  1. 首先会检查该对象的锁标志位。如果锁标志位为 0,表示没有线程持有锁,那么该线程会获取锁,将锁标志位设置为 1,并进入同步代码。
  2. 如果锁标志位为 1,表示已经有其他线程持有锁,当前线程会被阻塞,进入该对象的等待队列,直到持有锁的线程释放锁(执行完同步代码块或方法,或者发生异常),然后被唤醒并重新尝试获取锁。

注意事项

  • 性能开销:虽然synchronized能有效解决线程安全问题,但它会带来一定的性能开销,因为线程的阻塞和唤醒都需要消耗系统资源。因此,要避免过度使用,尽量只对关键代码进行同步。
  • 死锁问题:在使用synchronized修饰多个对象的代码块时,如果线程获取锁的顺序不一致,可能会导致死锁。比如线程 A 持有对象 X 的锁,等待获取对象 Y 的锁,而线程 B 持有对象 Y 的锁,等待获取对象 X 的锁,此时两个线程都无法继续执行。
  • 我们重点要理解,synchronized锁的是什么。两个线程竞争同⼀把锁,才会产生阻塞等待。 两个线程分别尝试获取两把不同的锁,不会产⽣竞争。
http://www.dtcms.com/a/267659.html

相关文章:

  • 从“电话催维修“到“手机看进度“——售后服务系统开发如何重构客户体验
  • Linux网络配置与故障排除完全指南
  • 12 nacos配置中心
  • 使用Kahn算法处理节点依赖关系
  • ABB焊接机器人智能节气仪
  • 汽车制造车间检测机器人与PLC无线以太网实时控制方案
  • 数据库学习笔记(十七)--触发器的使用
  • Java SE--数组
  • 前端相关性能优化笔记
  • TEXT Complete Search
  • 【RK3568 编译rtl8723DU驱动】
  • Write-up:hacker_dns
  • 安达发|告别低效排产:APS高级排程如何助力电池企业智造升级?
  • Java 大视界 -- 基于 Java 的大数据实时流处理在工业物联网设备能耗实时监测与节能优化中的应用(332)
  • 09_云原生架构:拥抱不确定性
  • 【力扣 简单 C】746. 使用最小花费爬楼梯
  • AI小智项目全解析:软硬件架构与开发环境配置
  • 自动化Prompt生成平台的研发体系设计
  • [HDLBits] Cs450/history shift
  • vue router 里push方法重写为什么要重绑定this
  • Xmind功能特点
  • LucidShape 2024.09 最新
  • 2025年3月青少年电子学会等级考试 中小学生python编程等级考试三级真题答案解析(判断题)
  • Docker文件操作、数据卷、挂载
  • Servlet学习
  • FFmpeg——基础知识及FFmpeg框架
  • MySQL GROUP_CONCAT函数实现列转行
  • 技术管理核心知识体系:从架构到实践的全方位指南
  • DPDK 网卡驱动
  • 堆叠初始化与配置同步工作机制(以IRF2.0为例)