Java并发编程实战--死锁
来源:互联网 发布:巴特尔cba数据 编辑:程序博客网 时间:2024/04/18 11:55
今天看了第十章,描述了经典的“哲学家进餐”问题,Google 哲学家进餐 就有 ,不多解释。先解释一下锁:可以这么理解,每一个java对象都具有一个锁标记,而这个锁标记只能同时分配给一个线程,然后讲了死锁的产生原因:当一个线程永远地持有一个锁,而且其他线程都想要取得这个锁时,那么它们将永远被阻塞。下面用三种介绍三种“死锁”状况。
一.死锁
先看代码
- package 并发编程;
- public class LeftRightDeadLock {
- //注意:容易发生死锁
- private final Object left = new Object();
- private final Object right = new Object();
- public void leftRight(){
- synchronized(left){
- synchronized(right){
- doSomething();
- }
- }
- }
- public void rightLeft(){
- synchronized(right){
- synchronized(left){
- doSomethingElse();
- }
- }
- }
- private void doSomethingElse() {
- }
- private void doSomething() {
- }
- }
上面的代码存在死锁的风险:leftRight()和rightLeft()分别获得left和right锁,如果A线程调用leftRight方法,而B线程调用rightLeft方法,而且他们是交错执行的,如下图,他们就有会出现死锁。
出现死锁的原因是:两个线程以不同顺序来获取相同的锁。如果以相同的顺序来获取锁,就不会出现循环的加锁依赖性,也就不会出现死锁。
二.动态的死锁
看代码
- package 并发编程;
- public class DynamicDeadLock {
- //注意:容易发生死锁 T.T
- public void transferMoney(Account from,Account to,DollarAmount num) throws Exception{
- synchronized(from){
- synchronized(to){
- if(from.getBalance().compareTo(num) < 0){
- throw new Exception();
- }
- from.debit(num);
- to.credit(num);
- }
- }
- }
- }
上面说了:如果以相同的顺序来获取相同的锁,就不会出现循环的加锁依赖性,也就不会出现死锁。在这个类中,只有一个方法,并且也是按照一个顺序来获取锁,应该不会有什么问题了吧?但实际上锁的获取是动态地取决于线程的行为,如果同时有A、B两个线程,A线程调用transferMoney(myBank,hisBank,1000),B线程调用transferMoney(myBank,hisBank,2000),实际上,A线程所谓的myBank其实是B线程的hisBank,A线程的hisBank其实是B线程的myBank,这样就导致两个线程获取锁的顺序不一样,产生了死锁。
三.协作对象间的死锁
先看两个类
- package 并发编程;
- /**
- * 出租车类,可被出租车车队调用
- * @author Andre
- *
- */
- public class Taxi {
- private Point location,destination;//包含两个属性:当前位置和目标地
- private final Dispatcher dispatcher;//所属车队
- public Taxi(Dispatcher dispatcher){
- this.dispatcher = dispatcher;
- }
- public synchronized Point getLocation(){
- return location;
- }
- /**
- * 通过GPS设置出租车位置
- * @param location
- */
- public synchronized void setLocation(Point location){
- this.location = location;
- if(location.equals(destination)){
- dispatcher.notifyAvailable(this);
- }
- }
- }
- package 并发编程;
- import java.awt.Image;
- import java.util.Set;
- /**
- * 出租车车队类,指挥出租车的调动
- * @author Andre
- *
- */
- public class Dispatcher {
- private final Set<Taxi> taxis;//出租车集合
- private final Set<Taxi> availableTaxis;///可用出租车集合
- public Dispatcher(Set<Taxi> taxis , Set<Taxi> availableTaxis){
- this.taxis = taxis;
- this.availableTaxis = availableTaxis;
- }
- public synchronized void notifyAvailable(Taxi taxi) {
- availableTaxis.add(taxi);
- }
- /**
- * 获得包含当前出租车的完整画面
- * @return
- */
- public synchronized CarImage getImage(){
- CarImage image = new CarImage();
- for(Taxi t: taxis)
- image.drawMarker(t.getLocation());
- return image;
- }
- }
- Java并发编程实战--死锁
- java并发编程实战笔记-死锁
- Java 并发编程之死锁
- Java并发编程:线程死锁
- Java并发编程实战
- Java并发编程实战--
- Java并发编程实战-
- Java 并发编程实战
- java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- MySQL命令行 不同端口登录 执行SQL文件 创建用户 赋予权限 修改root密码
- Maya: 菜单 编辑网格 >变换组件
- struts2格式化输出时间
- hdu--DP(必须掌握)
- 链表的逆置,归并,拆分以及其他函数集合
- Java并发编程实战--死锁
- Android原理之 View、ViewGroup
- Maya: 菜单 编辑网格 >翻转三角形边
- java反射|Reflection详解
- 用户管理的备份,恢复和还原知识点小结
- 整数各位数分离(C语言代码)
- 视频监控之VSCloud Camera 添加
- Maya: 菜单 编辑网格 >正向自旋边
- C# 线程之Thread