16、Java并发性和多线程-死锁
以下内容转自http://ifeve.com/deadlock/:
死锁是两个或更多线程阻塞着等待其它处于死锁状态的线程所持有的锁。死锁通常发生在多个线程同时但以不同的顺序请求同一组锁的时候。
例如,如果线程1锁住了A,然后尝试对B进行加锁,同时线程2已经锁住了B,接着尝试对A进行加锁,这时死锁就发生了。线程1永远得不到B,线程2也永远得不到A,并且它们永远也不会知道发生了这样的事情。为了得到彼此的对象(A和B),它们将永远阻塞下去。这种情况就是一个死锁。
该情况如下:
Thread 1 locks A, waits for B
Thread 2 locks B, waits for A
这里有一个TreeNode类的例子,它调用了不同实例的synchronized方法:
public class TreeNode {
TreeNode parent = null;
List children = new ArrayList();
public synchronized void addChild(TreeNode child){
if(!this.children.contains(child)) {
this.children.add(child);
child.setParentOnly(this);
}
}
public synchronized void addChildOnly(TreeNode child){
if(!this.children.contains(child){
this.children.add(child);
}
}
public synchronized void setParent(TreeNode parent){
this.parent = parent;
parent.addChildOnly(this);
}
public synchronized void setParentOnly(TreeNode parent){
this.parent = parent;
}
}
如果线程1调用parent.addChild(child)方法的同时有另外一个线程2调用child.setParent(parent)方法,两个线程中的parent表示的是同一个对象,child亦然,此时就会发生死锁。下面的伪代码说明了这个过程:
Thread 1: parent.addChild(child); //locks parent
--> child.setParentOnly(parent); Thread 2: child.setParent(parent); //locks child
--> parent.addChildOnly()
首先线程1调用parent.addChild(child)。因为addChild()是同步的,所以线程1会对parent对象加锁以不让其它线程访问该对象。
然后线程2调用child.setParent(parent)。因为setParent()是同步的,所以线程2会对child对象加锁以不让其它线程访问该对象。
现在child和parent对象被两个不同的线程锁住了。接下来线程1尝试调用child.setParentOnly()方法,但是由于child对象现在被线程2锁住的,所以该调用会被阻塞。线程2也尝试调用parent.addChildOnly(),但是由于parent对象现在被线程1锁住,导致线程2也阻塞在该方法处。现在两个线程都被阻塞并等待着获取另外一个线程所持有的锁。
注意:像上文描述的,这两个线程需要同时调用parent.addChild(child)和child.setParent(parent)方法,并且是同一个parent对象和同一个child对象,才有可能发生死锁。上面的代码可能运行一段时间才会出现死锁。
这些线程需要同时获得锁。举个例子,如果线程1稍微领先线程2,然后成功地锁住了A和B两个对象,那么线程2就会在尝试对B加锁的时候被阻塞,这样死锁就不会发生。因为线程调度通常是不可预测的,因此没有一个办法可以准确预测什么时候死锁会发生,仅仅是可能会发生。
更复杂的死锁
死锁可能不止包含2个线程,这让检测死锁变得更加困难。下面是4个线程发生死锁的例子:
Thread 1 locks A, waits for B
Thread 2 locks B, waits for C
Thread 3 locks C, waits for D
Thread 4 locks D, waits for A
线程1等待线程2,线程2等待线程3,线程3等待线程4,线程4等待线程1。
数据库的死锁
更加复杂的死锁场景发生在数据库事务中。一个数据库事务可能由多条SQL更新请求组成。当在一个事务中更新一条记录,这条记录就会被锁住避免其他事务的更新请求,直到第一个事务结束。同一个事务中每一个更新请求都可能会锁住一些记录。
当多个事务同时需要对一些相同的记录做更新操作时,就很有可能发生死锁,例如:
Transaction 1, request 1, locks record 1 for update
Transaction 2, request 1, locks record 2 for update
Transaction 1, request 2, tries to lock record 2 for update.
Transaction 2, request 2, tries to lock record 1 for update.
因为锁发生在不同的请求中,并且对于一个事务来说不可能提前知道所有它需要的锁,因此很难检测和避免数据库事务中的死锁。
16、Java并发性和多线程-死锁的更多相关文章
- java 并发性和多线程 -- 读感 (一 线程的基本概念部分)
1.目录略览 线程的基本概念:介绍线程的优点,代价,并发编程的模型.如何创建运行java 线程. 线程间通讯的机制:竞态条件与临界区,线程安全和共享资源与不可变性.java内存模型 ...
- Java并发性和多线程
Java并发性和多线程介绍 java并发性和多线程介绍: 单个程序内运行多个线程,多任务并发运行 多线程优点: 高效运行,多组件并行.读->操作->写: 程序设计的简单性,遇到多问题, ...
- Java并发性和多线程介绍
java并发性和多线程介绍: 单个程序内运行多个线程,多任务并发运行 多线程优点: 高效运行,多组件并行.读->操作->写: 程序设计的简单性,遇到多问题,多开线程就好: 快速响应,异步式 ...
- Java 并发和多线程(一) Java并发性和多线程介绍[转]
作者:Jakob Jenkov 译者:Simon-SZ 校对:方腾飞 http://tutorials.jenkov.com/java-concurrency/index.html 在过去单CPU时 ...
- Java高级教程:Java并发性和多线程
Java并发性和多线程: (中文,属于人工翻译,高质量):http://ifeve.com/java-concurrency-thread-directory/ (英文):http://tutoria ...
- 17、Java并发性和多线程-避免死锁
以下内容转自http://ifeve.com/deadlock-prevention/: 在有些情况下死锁是可以避免的.本文将展示三种用于避免死锁的技术: 加锁顺序 当多个线程需要相同的一些锁,但是按 ...
- Java 并发性和多线程
一.介绍 在过去单 CPU 时代,单任务在一个时间点只能执行单一程序.之后发展到多任务阶段,计算机能在同一时间点并行执行多任务或多进程.虽然并不是真正意义上的“同一时间点”,而是多个任务或进程共享一个 ...
- 1、Java并发性和多线程-并发性和多线程介绍
以下内容转自http://ifeve.com/java-concurrency-thread/: 在过去单CPU时代,单任务在一个时间点只能执行单一程序.之后发展到多任务阶段,计算机能在同一时间点并行 ...
- 6、Java并发性和多线程-并发性与并行性
以下内容转自http://tutorials.jenkov.com/java-concurrency/concurrency-vs-parallelism.html(使用谷歌翻译): 术语并发和并行性 ...
随机推荐
- MyEclipse日志文件目录
MyEclipse存放日志的目录为: <Workspace_Root>/.metadata/.log 在该目录下存放了日志的存档和当前日志,通过该日志可以查看MyEclipse的错误信息.
- Quartz.Net学习笔记(2)-简介
一.Quartz.Net是什么 1.来源 Quartz.Net是一个开源的作业调度框架: 2.下载地址 官网地址:http://www.quartz-scheduler.net/documentati ...
- ajax无限循环
// 猜你喜欢的无限加载 (function(){ var content = document.getElementsByClassName("content")[0]; var ...
- js this 和 event 的区别
今天在看javascript入门经典-事件一章中看到了 this 和 event 两种传参形式.因为作为一个初级的前端开发人员平时只用过 this传参,so很想弄清楚,this和event的区别是什么 ...
- 两个input可能会用到的小方法
1.一个普通的input元素,在不被 form包裹的时候,如何跳转或搜索 var oInput = document.getElementsByTagName('input')[0]; oInput. ...
- 详谈Struts+Hibernate+Spring三大框架
前言:对于JAVA WEB端的程序员来说,对JAVA三大框架:Struts+Hibernate+Spring的了解必不可缺,下面详细谈谈 Java三大框架主要用来做WEN应用. 三大框架:Struts ...
- Win7 下 PB (PowerBuilder) Insert Control 崩溃的解决办法
环境: WIN7 x86 PB8.0, x64系统目录不同,不过也可以试试 Insert -> OLE... -> Insert Control - 崩溃 如果网上提供的办法解决不了你 ...
- 隐藏win10任务栏输入法M图标
在任务栏右键=>任务栏设置=>打开或关闭系统图标=>(关闭)输入指示
- codeforces_456C_dp
链接:http://codeforces.com/problemset/problem/456/C C. Boredom time limit per test 1 second memory lim ...
- MySQL:INSERT ... UPDATE
在 INSERT 语句末尾指定ON DUPLICATE KEY UPDATE时,如果插入的数据会导致表中的 UNIQUE 索引或 PRIMARY KEY 出现重复值,则会对导致重复的数据执行 UPDA ...