Java多线程 线程同步与死锁
发布时间 - 2026-01-11 02:13:39 点击率:次Java多线程 线程同步与死锁

1.线程同步
多线程引发的安全问题
一个非常经典的案例,银行取钱的问题。假如你有一张银行卡,里面有5000块钱,然后你去银行取款2000块钱。正在你取钱的时候,取款机正要从你的5000余额中减去2000的时候,你的老婆正巧也在用银行卡对应的存折取钱,由于取款机还没有把你的2000块钱扣除,银行查到存折里的余额还剩5000块钱,准备减去2000。这时,有趣的事情发生了,你和你的老婆从同一个账户共取走了4000元,但是账户最后还剩下3000元。
使用代码模拟下取款过程:
public class ThreadTest {
public static void main(String[] args) {
// 创建一个账户,里面有存款5000元
Account account = new Account(5000);
// 模拟取钱过程
GetMoney getMoney = new GetMoney(account);
new Thread(getMoney, "你").start();
new Thread(getMoney, "你老婆").start();
}
}
class GetMoney implements Runnable {
private Account account;
public GetMoney(Account account) {
super();
this.account = account;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "账户现在有"
+ account.getMoney() + "元");
// 使效果更明显,休眠10ms
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
int money = account.getMoney() - 2000;
account.setMoney(money);
System.out.println(Thread.currentThread().getName() + "取了2000元,账户现在有"
+ account.getMoney() + "元");
}
}
class Account {
private int money;
public Account(int money) {
super();
this.money = money;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
看下打印信息:
你账户现在有5000元 你老婆账户现在有5000元 你取了2000元,账户现在有3000元 你老婆取了2000元,账户现在有3000元
同步锁
从上面的案例可以看出,当多个线程同时访问同一个数据时,很容易出现问题。为了避免这种情况出现,我们要保证线程同步互斥,就是指并发执行的多个线程,在同一时间内只允许一个线程访问共享数据。
Java中可以使用synchronized关键字来取得一个对象的同步锁。
// Object可以为任何对象,表示当前线程取得该对象的锁。
synchronized (Object) {
}
修改一下上面的案例,在run方法中加入同步锁:
@Override
public void run() {
synchronized (this) {
System.out.println(Thread.currentThread().getName() + "账户现在有"
+ account.getMoney() + "元");
// 使效果更明显,休眠10ms
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
int money = account.getMoney() - 2000;
account.setMoney(money);
System.out.println(Thread.currentThread().getName()
+ "取了2000元,账户现在有" + account.getMoney() + "元");
}
}
看下打印信息:
你账户现在有5000元 你取了2000元,账户现在有3000元 你老婆账户现在有3000元 你老婆取了2000元,账户现在有1000元
当你取钱的时候,取款机锁定了你的账户,不允许其他人对账户进行操作,当你取完钱后,取款机释放了你的账户,你的老婆才可以取钱。
2.死锁
同步锁虽好,但也要科学使用,不然就会发生死锁,何为死锁,就是多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。
举个栗子,两个人面对面过独木桥,甲和乙都已经在桥上走了一段距离,即占用了桥的资源,甲如果想通过独木桥的话,乙必须退出桥面让出桥的资源,让甲通过,但是乙不服,为什么让我先退出去,我还想先过去呢,于是就僵持不下,导致谁也过不了桥,这就是死锁。
下面用一段简单的代码来模拟死锁:
public class DeadlockTest {
public static void main(String[] args) {
String str1 = new String("资源1");
String str2 = new String("资源2");
new Thread(new Lock(str1, str2), "线程1").start();
new Thread(new Lock(str2, str1), "线程2").start();
}
}
class Lock implements Runnable {
private String str1;
private String str2;
public Lock(String str1, String str2) {
super();
this.str1 = str1;
this.str2 = str2;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + "运行");
synchronized (str1) {
System.out.println(Thread.currentThread().getName() + "锁住"
+ str1);
Thread.sleep(1000);
synchronized (str2) {
// 执行不到这里
System.out.println(Thread.currentThread().getName()
+ "锁住" + str2);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
看下打印信息:
线程1运行 线程2运行 线程1锁住资源1 线程2锁住资源2
第一个线程锁住了资源1(甲占有桥的一部分资源),第二个线程锁住了资源2(乙占有桥的一部分资源),线程1企图锁住资源2(甲让乙退出桥面,乙不从),进入阻塞,线程2企图锁住资源1(乙让甲退出桥面,甲不从),进入阻塞,死锁了。
死锁的产生是有规律可循的,只有同时满足以下四个条件,死锁才会产生。
1.互斥条件:一个资源每次只能被一个进程使用。独木桥每次只能通过一个人。
2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。乙不退出桥面,甲也不退出桥面。
3.不剥夺条件: 进程已获得的资源,在未使用完之前,不能强行剥夺。甲不能强制乙退出桥面,乙也不能强制甲退出桥面。
4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。如果乙不退出桥面,甲不能通过,甲不退出桥面,乙不能通过。
知道了死锁产生的必要条件,在开发中就很容易避免死锁问题了。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
# Java多线程
# 线程同步与死锁
# Java
# 线程同步
# Java多线程之死锁的出现和解决方法
# Java多线程产生死锁的必要条件
# java 多线程死锁详解及简单实例
# 如何解决Java多线程死锁问题
# Java多线程之死锁详解
# Java多线程死锁示例
# Java多线程死锁问题详解(wait和notify)
# 死锁
# 锁住
# 取钱
# 多个
# 取款机
# 走了
# 当你
# 很容易
# 多线程
# 人面
# 不从
# 就会
# 锁住了
# 也不
# 还没有
# 互斥
# 都在
# 是有
# 第一个
# 也要
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251811 】
【
AI营销90571 】
相关推荐:
Laravel的HTTP客户端怎么用_Laravel HTTP Client发起API请求教程
javascript中的数组方法有哪些_如何利用数组方法简化数据处理
家族网站制作贴纸教程视频,用豆子做粘帖画怎么制作?
html5源代码发行怎么设置权限_访问权限控制方法与实践【指南】
Laravel如何实现API资源集合?(Resource Collection教程)
如何用虚拟主机快速搭建网站?详细步骤解析
Android中AutoCompleteTextView自动提示
js实现点击每个li节点,都弹出其文本值及修改
如何在景安服务器上快速搭建个人网站?
Python图片处理进阶教程_Pillow滤镜与图像增强
Gemini怎么用新功能实时问答_Gemini实时问答使用【步骤】
Angular 表单中正确绑定输入值以确保提交与验证正常工作
如何在阿里云域名上完成建站全流程?
香港服务器网站卡顿?如何解决网络延迟与负载问题?
HTML 中如何正确使用模板变量为元素的 name 属性赋值
个人摄影网站制作流程,摄影爱好者都去什么网站?
如何快速生成橙子建站落地页链接?
如何在云主机快速搭建网站站点?
软银砸40亿美元收购DigitalBridge 强化AI资料中心布局
用v-html解决Vue.js渲染中html标签不被解析的问题
开心动漫网站制作软件下载,十分开心动画为何停播?
Laravel如何使用软删除(Soft Deletes)功能_Eloquent软删除与数据恢复方法
Laravel怎么实现一对多关联查询_Laravel Eloquent模型关系定义与预加载【实战】
非常酷的网站设计制作软件,酷培ai教育官方网站?
如何快速搭建高效香港服务器网站?
ChatGPT回答中断怎么办 引导AI继续输出完整内容的方法
香港网站服务器数量如何影响SEO优化效果?
Laravel如何生成URL和重定向?(路由助手函数)
桂林网站制作公司有哪些,桂林马拉松怎么报名?
Python函数文档自动校验_规范解析【教程】
深圳防火门网站制作公司,深圳中天明防火门怎么编码?
Win11怎么恢复误删照片_Win11数据恢复工具使用【推荐】
Laravel如何使用Socialite实现第三方登录?(微信/GitHub示例)
Laravel Docker环境搭建教程_Laravel Sail使用指南
Laravel模型关联查询教程_Laravel Eloquent一对多关联写法
Laravel Eloquent性能优化技巧_Laravel N+1查询问题解决
如何在IIS管理器中快速创建并配置网站?
黑客如何通过漏洞一步步攻陷网站服务器?
Laravel如何创建和注册中间件_Laravel中间件编写与应用流程
Laravel Pest测试框架怎么用_从PHPUnit转向Pest的Laravel测试教程
如何快速登录WAP自助建站平台?
Laravel怎么进行数据库回滚_Laravel Migration数据库版本控制与回滚操作
Laravel怎么判断请求类型_Laravel Request isMethod用法
绝密ChatGPT指令:手把手教你生成HR无法拒绝的求职信
JavaScript数据类型有哪些_如何准确判断一个变量的类型
百度浏览器如何管理插件 百度浏览器插件管理方法
如何在Tomcat中配置并部署网站项目?
宙斯浏览器视频悬浮窗怎么开启 边看视频边操作其他应用教程
JavaScript如何实现类型判断_typeof和instanceof有什么区别
如何用JavaScript实现文本编辑器_光标和选区怎么处理
下一篇:ubuntu软连接故障怎么排查
下一篇:ubuntu软连接故障怎么排查

