博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
死锁机制
阅读量:5052 次
发布时间:2019-06-12

本文共 4639 字,大约阅读时间需要 15 分钟。

  • 介绍: 死锁是由于不同的进程拥有对方需要的被锁资源,又在相互请求对方的被锁资源造成的无限等待局面

1 JAVA中的死锁

1.1 死锁示例

两个死锁类

1 package deadlock; 2  3 import java.util.List; 4  5 public class A extends Thread { 6     private List listA; //A,B两个类共享同一个listA和listB 7     private List listB; 8  9     public A(List listA, List listB) {10         this.listA = listA;11         this.listB = listB;12     }13 14     public void lockListA() {15         synchronized (listA) {  //请求listA的对象锁16             System.out.println("listA locked");17             try {18                 sleep(2 * 1000);    //休息2秒19             } catch (InterruptedException e) {20                 e.printStackTrace();21             }22             synchronized (listB) {  //请求listB的对象锁23                 listB.add("B");24                 System.out.println(listB.toString());25             }26         }27         System.out.println("listA unlocked");28 29     }30 31     public void run() {32         lockListA();33     }34 }
1 package deadlock; 2  3 import java.util.List; 4  5 public class B extends Thread{ 6     private List listA; 7     private List listB; 8  9     public B(List listA, List listB) {10         this.listA = listA;11         this.listB = listB;12     }13 14     public void lockListB() {15         synchronized (listB) {16             System.out.println("listB locked");17             try {18                 sleep(5 * 1000);19             } catch (InterruptedException e) {20                 e.printStackTrace();21             }22             synchronized (listA) {23                 listA.add("A");24                 System.out.println(listA.toString());25             }26         }27         System.out.println("listB unlocked");28 29     }30 31     public void run() {32         lockListB();33     }34 }

 

运行主方法

1 package deadlock; 2  3 import java.util.ArrayList; 4 import java.util.List; 5  6 public class Test { 7     public static void main(String[] args) { 8         List a = new ArrayList(); 9         List b = new ArrayList();10 11         A threadA = new A(a, b);12         B threadB = new B(a, b);13 14         threadA.start();15         threadB.start();16     }17 }

 

运行结果: 

listA locked

listB locked

 可以看到locked以后就不能unlocked了,也就是进入了死锁,听我分析:

  1. threadA.start()调用了lockListA()方法,这时候listA的对象锁被threadA获取,然后threadA进入sleep 2秒的过程
  2. threadB.start()调用了lockListB()方法,这时候listB的对象锁被threadB获取,然后threadB进入sleep 5秒的过程
  3. 2秒后,threadA醒来,threadA请求listB的对象锁,此时threadB处于sleep状态,listB的对象锁被threadB持有,所以threadA坐等threadB释放对象锁
  4. 又过了3秒,threadB醒来,threadB请求listA的对象锁,此时threadA处于等待阻塞状态(正在等threadB释放listB的对象锁),还没有释放listA的锁,所以threadB也只有等待threadA释放listA的对象锁,于是threadB也进入阻塞状态
  5. 于是,threadA和threadB都进入了阻塞,于是就无限阻塞下去了...

 

1.2 同步方法的常用写法

一般来说,我们在写线程安全的方法时都会这样写,如下:

1 package threadsafe; 2  3 import java.util.ArrayList; 4 import java.util.List; 5  6 public class ThreadSafeClass { 7     List
intList; 8 9 public ThreadSafeClass() {10 intList = new ArrayList
();11 }12 13 public void addElement() {14 synchronized (this) { //调用此方法是,将自己锁死15 Integer elem = (int)(Math.random() * 100);16 intList.add(elem);17 }18 }19 }
1 package threadsafe; 2  3 import java.util.ArrayList; 4 import java.util.List; 5  6 public class MyThread extends Thread{ 7     ThreadSafeClass threadSafeClass; 8  9     public MyThread(ThreadSafeClass tsc) {10         threadSafeClass = tsc;11     }12 13     public void run() {14         threadSafeClass.addElement();   //多线程执行此方法只能一步一步来,因为要获取本对象锁15     }16 }

 

 

1.4 JAVA自己实现的线程安全类

1.4.1 Vector一族

先谈谈Vector和ArrayList,我们都知道Vector和ArrayList功能类似,他们的区别在于Vector是线程安全的,而ArrayList不是,那么Vector的线程安全是如何实现的呢

查看源码可以发现他的方法多是synchronized的(这里我就不贴源码了,有兴趣的同学可以去查查),也就是说他的实现和我上面说的类似,这种方法的缺点其实就是效率比较低下,因为加锁是很消耗效率的

 

1.4.2 ConccurentLinkedQueue

这里以ConcurrentLinkedQueue为例,查看源码看不到synchronized之类的东西,这里引用网摘的一段话:

先来回顾之前提到过的ConcurrentHashMap,它是一个以Concurrent开头的并发集合类,其原理是通过增加锁和细化锁的粒度来提高并发度。
另一个值得一提的Concurrent是
ConcurrentLinkedQueue。这个类采用了另一种提高并发度的方式:非阻塞算法(Non-blocking),第一次实现了无锁的并发。

也就是说ConcurrentLinkedQueue并不是采用加锁的方式实现线程同步的,这个非阻塞算法大家有兴趣可以去研究一下

 

2 数据库中的死锁

数据库中的死锁常出现在事物中,这里我不写具体的代码了,举个例子随便聊聊

比如数据库中有两个表

现在又两个事务:

事务A:

1 BEGIN;2 3 SELECT * FROM user WHERE userId = ? FOR UPDATE;4 5 DELETE FROM message WHERE messageId = ?;6 7 COMMIT;

 

事务B:

1 BEGIN;2 3 SELECT * FROM message WHERE messageId = ? FOR UPDATE;4 5 UPDATE user SET userName = 'test' WHERE userId = ?;6 7 COMMIT;

 

假设现在两个事务同时运行,userId = 1, messageId = 1,就会造成死锁

因为事务A首先对userId=1的那行加上行锁,事务B也同时对messageId=1的那行加上行锁

然后事务A想DELETE messageId=1的那行,就必须等待事务B结束,释放messageId=1的那行的行锁

而事务B想UPDATE userId=1的那行,也必须等待事务A结束,释放userId=1的那行的行锁

这样相互等待,就死锁了

转载于:https://www.cnblogs.com/zemliu/archive/2012/05/16/2503725.html

你可能感兴趣的文章
一张图看懂LiveGBS(国标流媒体GB28181)与LiveQing的关系
查看>>
贪婪和恐惧
查看>>
数据库之 :分页技术:之点击一次取一次数据
查看>>
JavaScript
查看>>
VS2008开发Windows Mobile6环境搭建及模拟器联网问题图解
查看>>
V2019 Super DSP3 Odometer Correction Vehicle List
查看>>
Python 3.X 练习集100题 05
查看>>
4sumii
查看>>
手写API接口测试使用的两个函数
查看>>
canvas
查看>>
实验三观后感
查看>>
Java系列学习(零)-写在前面的话
查看>>
Python模块
查看>>
”win7笔记本共享无线网络,手机连接成功却无法上网“的解决之道【亲身经历】...
查看>>
今时不同往日:VS2010十大绝技让VS6叹服
查看>>
设计器 和后台代码的转换 快捷键
查看>>
在线视频播放软件
查看>>
用代码生成器生成的DAL数据访问操作类 基本满足需求了
查看>>
28初识线程
查看>>
Monkey测试结果分析
查看>>