news 2026/6/5 9:21:42

Java线程安全和同步

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java线程安全和同步

目录

1.场景

2.编写程序

3.解决办法:线程同步

1)synchronized同步代码块

2)synchronized同步方法

3)两个方式的对比

4)写一个锁对象

4.使用场景

使用Lock的场景

使用synchronized的场景


1.场景

小明和小红是一对夫妻,他们有一个共同的账户,有余额十万块钱,有一天他们各自同时取了十万块钱。那谁能成功取到这十万呢?

2.编写程序

1)创建账户类,创建账户对象来代表夫妻的共同账户,提供取钱方法

package ThreadSecurity; public class Account { private Integer money; public Account() {} public Account(Integer money) { this.money = money; } public Integer getMoney() { return money; } public void setMoney(Integer money) { this.money = money; } //取钱方法 public void drawMoney(Integer money) { //看看是谁来取钱 String name = Thread.currentThread().getName(); //验证余额 if (this.money >= money) { //先打印一次,以免程序执行过快反而不出现安全问题 System.out.println(name+"取钱成功,取出了"+money+"元"); this.money -= money ; System.out.println(name + "取钱成功,余额" + this.money + "元"); } else { System.out.println("余额不足"); } } }

2)使用线程类,运行两个线程来模拟取钱过程

package ThreadSecurity; public class MyThread implements Runnable{ private Account account; public MyThread(Account account) { this.account = account; } @Override public void run() { account.drawMoney(100000); } }

3)测试

package ThreadSecurity; /** * 模拟线程同步问题 * 小明和小红同时取同一个账户的钱 */ public class Test { public static void main(String[] args) { //创建账户类 Account account = new Account(100000); //创建小明线程 Thread xm=new Thread(new MyThread(account)); xm.setName("小明"); xm.start(); //创建小红线程 Thread xh=new Thread(new MyThread(account)); xh.setName("小红"); xh.start(); } }

结果:(也有可能是小红取钱成功)

可见,如果两个人都取钱成功,那么银行就会亏损十万元。

那么该怎么解决呢?

3.解决办法:线程同步

1)synchronized同步代码块

作用:把访问共享资源的核心代码块上锁,以此保证线程安全

在核心逻辑取钱方法当中修改:

package ThreadSynchronized01; public class Account { private Integer money; public Account() {} public Account(Integer money) { this.money = money; } public Integer getMoney() { return money; } public void setMoney(Integer money) { this.money = money; } //取钱方法 public void drawMoney(Integer money) { //看看是谁来取钱 String name = Thread.currentThread().getName(); //synchronized代码块:给代码块上锁 //线程通过竞争锁,拿到锁对象(this)之后可以执行代码块,执行完之后释放 synchronized (this) { //验证余额 if (this.money >= money) { //先打印一次,以免程序执行过快反而不出现安全问题 System.out.println(name+"取钱成功,取出了"+money+"元"); this.money -= money ; System.out.println(name + "取钱成功,余额" + this.money + "元"); } else { System.out.println(name+"取钱失败,余额不足"); } } } }

语法

synchronized(锁对象){

//业务逻辑......

}

锁对象可以是其他对象,但是不建议,因为如果是某一常量的话,可能会影响其他无关线程的运行。用this合适,因为这样不会影响其他无关线程的执行,也能起到锁的作用。

对于实例方法,建议使用this作为锁对象

对于静态方法,建议使用字节码(类名.class)作为锁对象

执行结果:(结果不唯一)

2)synchronized同步方法

作用:把访问共享资源的核心方法上锁,以此保证线程安全

修改取钱方法:

package ThreadSynchronized02; public class Account { private Integer money; public Account() {} public Account(Integer money) { this.money = money; } public Integer getMoney() { return money; } public void setMoney(Integer money) { this.money = money; } //取钱方法 //synchronized同步方法,和synchronized代码块大致相同 //synchronized方法的性能比synchronized代码块低,因为synchronized代码块可以让其他线程先处理没有线程安全的代码 //synchronized同步方法维护了一个隐式锁 public synchronized void drawMoney(Integer money) { //看看是谁来取钱 String name = Thread.currentThread().getName(); //验证余额 if (this.money >= money) { //先打印一次,以免程序执行过快反而不出现安全问题 System.out.println(name+"取钱成功,取出了"+money+"元"); this.money -= money ; System.out.println(name + "取钱成功,余额" + this.money + "元"); } else { System.out.println(name+"取钱失败,余额不足"); } } }

结果:(结果不唯一)

3)两个方式的对比

4)写一个锁对象

Lock是Java并发包java.util.concurrent.locks中提供的显式锁机制,相比synchronized内置锁,它提供了更灵活、功能更丰富的锁控制

以ReentrantLock(可重入锁)为例:

package ThreadLock; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Account { //锁对象,加上final防止锁被修改 private final Lock lock = new ReentrantLock(); private Integer money; public Account() {} public Account(Integer money) { this.money = money; } public Integer getMoney() { return money; } public void setMoney(Integer money) { this.money = money; } //取钱方法 public void drawMoney(Integer money) { //看看是谁来取钱 String name = Thread.currentThread().getName(); //ctrl+alt+t选中代码块 try { //上锁 lock.lock(); //验证余额 if (this.money >= money) { //先打印一次,以免程序执行过快反而不出现安全问题 System.out.println(name+"取钱成功,取出了"+money+"元"); this.money -= money ; System.out.println(name + "取钱成功,余额" + this.money + "元"); } else { System.out.println("余额不足"); } } catch (Exception e) { throw new RuntimeException(e); }finally { //unlock必须执行,如果前面发生异常,也要解锁,所以要在finally里面 lock.unlock(); } } }

结果(不唯一):

4.使用场景

使用Lock的场景

需要高级功能:可中断、超时、尝试锁

需要多个条件变量:复杂的线程协调

读写分离场景:读多写少

需要公平性控制:按顺序获取锁

性能关键场景:高竞争下的性能优化

使用synchronized的场景

简单同步需求:基本的互斥访问

代码简洁性:减少代码复杂度

自动管理:避免忘记释放锁

内建优化:JVM对synchronized有深度优化

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/5 7:10:20

工业质检Agent如何突破瓶颈?3种前沿算法在复杂场景下的应用对比

第一章:工业质检 Agent 的缺陷识别在现代智能制造体系中,工业质检 Agent 扮演着关键角色,其核心任务是通过自动化手段实现对生产线产品的实时缺陷检测。这类 Agent 通常集成计算机视觉、深度学习与边缘计算技术,能够在毫秒级时间内…

作者头像 李华
网站建设 2026/6/1 23:51:59

【自动驾驶Agent地图更新终极指南】:揭秘高精地图实时演进核心技术

第一章:自动驾驶Agent地图更新概述自动驾驶系统依赖高精度地图实现环境感知、路径规划与决策控制。随着道路基础设施的动态变化,静态地图已无法满足实时性需求,因此引入自动驾驶Agent进行地图更新成为关键技术方向。这些Agent通过车载传感器采…

作者头像 李华
网站建设 2026/6/5 3:57:48

【云边协同架构设计必读】:掌握这7种任务分配策略,性能提升300%

第一章:云边协同Agent任务分配的核心挑战在构建云边协同系统时,Agent任务分配面临多重技术挑战。由于边缘节点资源受限、网络延迟波动大以及任务类型多样化,传统的集中式调度策略难以满足实时性与能效的双重需求。动态资源感知的难度 边缘设备…

作者头像 李华
网站建设 2026/6/1 3:27:30

【AI系统安全必修课】:掌握Agent权限管理的7个核心原则

第一章:Agent权限管理的核心挑战在现代分布式系统与自动化运维架构中,Agent作为连接控制中心与终端节点的关键组件,承担着指令执行、数据采集和状态上报等核心职能。然而,随着系统规模扩大和异构环境增多,如何对Agent实…

作者头像 李华
网站建设 2026/6/4 20:49:39

核心通用材料(所有行业必备)​

1. 主体资质文件(证明 “谁在办”)​✅ 营业执照副本扫描件(需加盖公章)​✅ 法定代表人身份证正反面扫描件​✅ 算法安全责任人材料:姓名 身份证号 联系方式 工作证明(劳动合同 / 社保记录)…

作者头像 李华