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

三种 synchronized 锁方式详解

1. 普通同步方法:锁是当前实例对象(this)

语法形式
public synchronized void method() { // 业务逻辑 }
本质等价写法

普通同步方法等价于在方法体内用synchronized(this)包裹代码,锁对象是调用该方法的当前实例对象

public void method() { synchronized (this) { // 锁 = 当前实例对象 // 业务逻辑 } }
案例演示
public class Data { // 普通同步方法:锁 this public synchronized void fun1() { try { Thread.sleep(3000); // 模拟耗时操作,持有锁3秒 System.out.println("1111111"); } catch (InterruptedException e) { e.printStackTrace(); } } // 普通同步方法:锁 this(和 fun1 共享同一把锁) public synchronized void fun2() { System.out.println("2222222"); } } // 测试类 public class SyncTest1 { public static void main(String[] args) { Data data = new Data(); Thread t1 = new Thread(() -> data.fun1()); Thread t2 = new Thread(() -> data.fun2()); t1.start(); t2.start(); } }

执行结果

(等待约3秒) 1111111 2222222

核心结论

  • 锁对象是this,只有同一个实例对象的同步方法才会互斥。
  • 不同实例对象的同步方法互不影响(比如new Data().fun1()new Data().fun2()不会阻塞)。
  • 适合实例级别的线程安全场景,比如操作单个对象的共享资源。

2. 静态同步方法:锁是当前类的 Class 对象

语法形式
public static synchronized void staticMethod() { // 业务逻辑 }
本质等价写法

静态同步方法等价于在方法体内用synchronized(类名.class)包裹代码,锁对象是当前类的 Class 对象(全局唯一):

public static void staticMethod() { synchronized (Data.class) { // 锁 = 当前类的 Class 对象 // 业务逻辑 } }
案例演示
public class Data { // 静态同步方法:锁 Data.class public static synchronized void staticFun1() { try { Thread.sleep(3000); System.out.println("1111111 (static)"); } catch (InterruptedException e) { e.printStackTrace(); } } // 静态同步方法:锁 Data.class(和 staticFun1 共享同一把锁) public static synchronized void staticFun2() { System.out.println("2222222 (static)"); } } // 测试类 public class SyncTest2 { public static void main(String[] args) { Thread t1 = new Thread(() -> Data.staticFun1()); Thread t2 = new Thread(() -> Data.staticFun2()); t1.start(); t2.start(); } }

执行结果

(等待约3秒) 1111111 (static) 2222222 (static)

核心结论

  • 锁对象是类名.class,全局唯一,无论创建多少个实例,所有线程调用该类的静态同步方法都会竞争同一把锁。
  • 适合类级别的全局线程安全场景,比如操作静态共享资源(如静态计数器、单例对象)。

3. 同步代码块:锁是 synchronized 括号内配置的对象

语法形式
synchronized (锁对象) { // 业务逻辑 }

同步代码块是最灵活的方式,可以自由指定锁对象,常见有三种写法:

写法 1:锁 this(和普通同步方法等价)
public void fun1() { synchronized (this) { // 锁当前实例 try { Thread.sleep(3000); System.out.println("1111111 (block this)"); } catch (InterruptedException e) { e.printStackTrace(); } } } public void fun2() { synchronized (this) { // 和 fun1 共享 this 锁 System.out.println("2222222 (block this)"); } }

效果:和普通同步方法完全一致,同一实例的方法互斥。

写法 2:锁 Class 对象(和静态同步方法等价)
public void fun1() { synchronized (Data.class) { // 锁类对象 try { Thread.sleep(3000); System.out.println("1111111 (block class)"); } catch (InterruptedException e) { e.printStackTrace(); } } } public void fun2() { synchronized (Data.class) { // 和 fun1 共享类锁 System.out.println("2222222 (block class)"); } }

效果:和静态同步方法完全一致,全局互斥。

写法 3:锁自定义对象(细粒度锁,推荐)

这是最推荐的写法,可以实现更细粒度的锁控制,避免不必要的互斥:

public class Data { // 自定义锁对象(private final 防止外部修改) private final Object lock1 = new Object(); private final Object lock2 = new Object(); public void fun1() { synchronized (lock1) { // 只锁 lock1 try { Thread.sleep(3000); System.out.println("1111111 (block lock1)"); } catch (InterruptedException e) { e.printStackTrace(); } } } public void fun2() { synchronized (lock2) { // 锁 lock2,和 lock1 互不干扰 System.out.println("2222222 (block lock2)"); } } } // 测试类 public class SyncTest3 { public static void main(String[] args) { Data data = new Data(); Thread t1 = new Thread(() -> data.fun1()); Thread t2 = new Thread(() -> data.fun2()); t1.start(); t2.start(); } }

执行结果

2222222 (block lock2) (等待约3秒) 1111111 (block lock1)

核心结论

  • 锁对象可以是任意引用类型(推荐用private final Object自定义锁)。
  • 可以只锁关键代码段,减少锁持有时间,提升并发性能。
  • 适合复杂同步场景,比如需要对不同资源分别加锁的场景。

三、三种锁方式对比总结

锁方式锁对象作用范围适用场景互斥表现
普通同步方法this(当前实例)同一对象的所有同步方法实例级别线程安全同一实例的方法互斥,不同实例不互斥
静态同步方法类名.class(Class 对象)整个类的所有静态同步方法类级别全局线程安全所有实例的静态方法全局互斥
同步代码块括号内指定的任意对象由锁对象决定,灵活可控细粒度锁、性能优化同一锁对象的代码块互斥,不
http://www.jsqmd.com/news/517380/

相关文章:

  • 肇庆星车驾到车身改色口碑如何,值得选择吗? - 工业品牌热点
  • 从Excel到预测:TCN-Attention时间序列实战,Matlab一键运行!
  • VS2022实战:5分钟搞定NPOI安装与Excel读写(附完整代码)
  • Android13照片选择器深度解析:权限优化与高效集成指南
  • AutoxJS避坑指南:从按钮点击失败到root权限问题的全面解决方案
  • 如何彻底优化Windows 11系统:Win11Debloat专业级系统清理工具实战指南
  • 信息论中的编码类型:从奇异码到即时码的实战应用指南
  • 别再只会写计数器了!通过这个数字时钟项目,深入理解Verilog中的时序逻辑设计精髓
  • Gemini Pro 2.5免费额度怎么用?Java开发者成本优化实操手册
  • 半导体测试数据入门:5个STDF文件解析的常见误区及解决方法
  • Qwen-Image-Edit-F2P模型在C语言项目中的调用接口设计
  • 相控阵雷达开发避坑指南:数据立方体生成中的5个常见错误与解决方案
  • FPGA新手必看:Lattice Diamond 3.14安装到点灯全流程(附免费License申请攻略)
  • Python实战:5种非参数估计方法代码实现(附KDE、KNN示例)
  • 单片机代码执行的硬件本质:从晶体管到指令运行
  • Linux网络排查利器:ss命令的5个实战技巧(附真实案例)
  • 你的 Go 报错信息正在“出卖”你!扒一扒大厂是如何做错误隔离与日志脱敏的
  • Python词频统计避坑指南:为什么你的Counter比原生字典慢?
  • Fluent仿真必看:如何正确设置边界条件避免计算结果失真?
  • Phi-3-mini-128k-instruct视觉理解延伸:结合YOLOv8实现图文多模态分析
  • AI前端开发全攻略:6个月转型路线+5大核心能力详解
  • 20252915时进旭 2025-2026-2 《网络攻防实践》第二周作业
  • “小数据”与大数据(之一)
  • Python调用FFmpeg报错127?手把手教你解决libopenh264.so.5缺失问题(附conda安装指南)
  • SMP心路历程(之八)
  • microchip dspic33 系列教程(4):MCC配置UART实现智能卡通信协议
  • 2026年,观音桥必吃招牌江湖菜品牌评测大揭秘,市面上热门的招牌江湖菜厂家口碑分析解析品牌实力与甄选要点 - 品牌推荐师
  • 视觉SLAM必备:Pangolin 0.5版本在Ubuntu20.04上的完整配置流程(兼容ORB-SLAM2)
  • 程序员转型大模型:机遇还是陷阱?小白必看的深耕指南
  • 三人表决电路设计避坑指南:从真值表到74LS54实战