Java多线程——死锁
当一个线程永远地持有一个锁,并且其他线程都尝试获得这个锁时,那么他永远被阻塞,当线程A持有锁L并想获得锁M的同时,线程B持有锁M并同时尝试获得锁L时,那么两个线程将永远的等待下去,这中情况就是简单的死锁的形式,其中多个线程由于存在环路的锁依赖关系而永远的等待下去,那么就存在一个死锁。
1、锁顺序死锁
下面是顺序锁的一个列子,代码如下:
package deadLock;
public class LeftRightDeadLock {
private final Object left = new Object();
private final Object right = new Object();
public void leftRight() throws Exception{
synchronized (left) {
Thread.sleep(2000);
synchronized (right) {
System.out.println("left to right");
}
}
}
public void rightLeft() throws Exception{
synchronized (right) {
Thread.sleep(2000);
synchronized (left) {
System.out.println("right to left");
}
}
}
}
package deadLock;
public class LeftRightThread extends Thread {
private LeftRightDeadLock d;
public LeftRightThread(LeftRightDeadLock d){
this.d = d;
}
@Override
public void run() {
try{
d.leftRight();
}catch(Exception ex){
ex.printStackTrace();
}
}
}
package deadLock;
public class RightLeftThread extends Thread {
private LeftRightDeadLock d;
public RightLeftThread(LeftRightDeadLock d){
this.d = d;
}
@Override
public void run() {
try{
d.rightLeft();
}catch(Exception ex){
ex.printStackTrace();
}
}
}
package deadLock;
public class Main {
public static void main(String[] args) {
LeftRightDeadLock d = new LeftRightDeadLock();
LeftRightThread t1 = new LeftRightThread(d);
RightLeftThread t2 = new RightLeftThread(d);
t1.start();
t2.start();
}
}
线程t1持有left的锁,并尝试获取得right的锁,而线程t2持有right的锁,并尝试获得left的锁,故产生死锁。产生死锁的原因是:两个线程试图以不同的顺序来获得相同的锁,如果按照相同的顺序来请求锁,那么就不会出现循环的加锁依赖性,因此也就不会产生死锁。
如果所有线程以固定的顺序来获得锁,那么在程序中就不会出现锁顺序死锁的问题
2、动态的锁顺序死锁
有时候,并不能清楚的知道是否在锁顺序上有足够的控制权来避免死锁的发生,看如下转账的代码。
public class TransferAccounts {
public void transferMoney(Account fromAccount, Account toAccount, double amount) throws Exception{
synchronized (fromAccount) {
synchronized (toAccount) {
if(fromAccount.getBalance() - amount < 0){
throw new Exception();
}
else{
fromAccount.setBalance(amount);
toAccount.add(amount);
}
}
}
}
}
public class Account {
//金额
private double balance;
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public void add(double amount){
balance += amount;
}
public void subtra(double amount){
balance -= amount;
}
}
上面代码是资金从一个账户转到另一个账户的简单实现,在开始转账之前要获得这两个Account对象的锁,以确保通过原子方式来更新两个账户的中余额。所有的线程似乎都是按照顺序锁来获得锁,但是事实上锁的顺序取决于转给函数transferMoney参数顺序,而这些参数又取决于外部的输入,如果两个线程同时调用transferMoney,其中一个线程从X向Y转账,另一个线程从Y向X转账,有可能发生死锁:
线程A:transferMoney(xAccount, yAccount);
线程B:transferMoney(yAccount, xAccount);
为了防止这种情况发生,必须按照顺序来获取锁。如下代码:
public class TransferAccounts {
private static final Object tieLock = new Object();
public void transfer(Account fromAccount, Account toAccount,
double amount) throws Exception {
if (fromAccount.getBalance() - amount < 0) {
throw new Exception();
} else {
fromAccount.setBalance(amount);
toAccount.add(amount);
}
}
public void transferMoney(Account fromAccount, Account toAccount,
double amount) throws Exception{
int fromHash = fromAccount.hashCode();
int toHash = toAccount.hashCode();
if(fromHash < toHash){
synchronized (fromAccount) {
synchronized (toAccount) {
transfer(fromAccount, toAccount, amount);
}
}
}else if(fromHash > toHash){
synchronized (toAccount) {
synchronized (fromAccount) {
transfer(fromAccount, toAccount, amount);
}
}
}else {
synchronized (tieLock) {
synchronized (fromAccount) {
synchronized (toAccount) {
transfer(fromAccount, toAccount, amount);
}
}
}
}
}
}
在极少数的情况下,两个对象可能拥有相对的hashCode值,这时必须通过添加额外的锁来,在获得两个Account的锁之前,必须先获得这个额外的锁。从而消除死锁的发生。
3、死锁的避免与诊断
(1) 如果一个程序每次至多只能获取一个锁,那么就不会产生锁顺序死锁。
(2) 如果必须获取多个锁,那么设计时必须考虑锁的顺序,如果按照固定的顺序来获取锁,就不会发生锁顺序死锁。
(3)支持定时锁,例如显示使用Lock类中的定时tryLock功能来代替内置锁,显示锁可以指定一个超时时限,在等待超过某个时间后tryLock会返回一个失败的信息。
Java多线程——死锁的更多相关文章
- Java 多线程 死锁 隐性死锁 数据竞争 恶性数据竞争 错误解决深入分析 全方向举例
在几乎所有编程语言中,由于多线程引发的错误都有着难以再现的特点,程序的死锁或其它多线程错误可能只在某些特殊的情形下才出现,或在不同的VM上运行同一个程序时错误表现不同.因此,在编写多线程程序时,事先认 ...
- Java 多线程 --死锁及解决方案
在java 多线程中 过多的同步造成相互不释放资源 从而相互等待,造成死锁线现象,一般发生于同步中持有多个对象锁 如以下代码: public class DeadLock { public stati ...
- java多线程--死锁
1. Java中导致死锁的原因 Java中死锁最简单的情况是,一个线程T1持有锁L1并且申请获得锁L2,而另一个线程T2持有锁L2并且申请获得锁L1,因为默认的锁申请操作都是阻塞的,所以线程T1和T2 ...
- Java 多线程 - 死锁deadlock产生原因+避免方法
ref: java中产生死锁的原因及如何避免 https://blog.csdn.net/m0_38126177/article/details/78587845 java如何避免死锁 http:// ...
- Java多线程死锁的产生实例
死锁产生的四个必要条件: (1) 互斥条件:一个资源每次只能被一个进程使用.(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放.(3) 不剥夺条件:进程已获得的资源,在末使用完 ...
- java 多线程死锁
死锁案例: package com.test; public class DealThread implements Runnable { public String username; public ...
- java多线程死锁
进程(线程)同步的基本概念 进程之间的制约关系 1. 直接制约关系(进程同步) 这个关系主要源于进程合作,例如,有一个输入进程A通过单缓冲向进程B提供数据,当该缓冲空时,进程B因为不能获得所需数据而被 ...
- Java多线程编程核心技术(二)对象及变量的并发访问
本文主要介绍Java多线程中的同步,也就是如何在Java语言中写出线程安全的程序,如何在Java语言中解决非线程安全的相关问题.阅读本文应该着重掌握如下技术点: synchronized对象监视器为O ...
- Java多线程中的死锁问题
Java程序基本都要涉及到多线程,而在多线程环境中不可避免的要遇到线程死锁的问题.Java不像数据库那么能够检测到死锁,然后进行处理,Java中的死锁问题,只能通过程序员自己写代码时避免引入死锁的可能 ...
随机推荐
- list集合如何对里面的元素进行排序
Collections 是集合的公共类,提供各种工具,其中提供了排序方法. Collections.sort(),方法两个参数,1,要排序的集合,2.排序方式 下面是匿名内部类,实现了排序借口,你也可 ...
- hdu-1698(线段树,区间修改)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1698 注意:用位运算会更快,不然超时. #include<iostream> #inclu ...
- 继承方法-->call继承
function Person(name,age,sex){ this.name = name; this.age = age; this.sex = sex; }function P1(name,a ...
- Win7_Ultimate + VS2010 + openGL_MFC单文档应用开发框架搭建步骤
Win7_Ultimate + VS2010 + openGL单文档应用开发框架搭建步骤 上一个配置是基于OpenGL的开发工具配置的,下面就是基于Vs2010的MFC单文档应用开发. 通过网上查找资 ...
- hdu 4993
http://acm.hdu.edu.cn/showproblem.php?pid=4993 满足ax + by = c的x,y对数 水题,暴力 #include <cstdio> #in ...
- maven下@override标签失效
经常遇见此问题,现记录如下,以备下次查阅. 在pom文件添加配置: <plugin> <groupId>org.apache.maven.plugins</groupId ...
- 在MS单元测试中引发期望异常
首先准备一个引发异常的方法. public static void ThrowException() { throw new ArgumentException(); } 然后在单元测试项目中,写下测 ...
- Mac iTerm2登陆CentOS提示warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory
[报错原因]:没有utf-8这个语系(没添加语言_国名前缀),LC_ALL又没设定值. 服务端解决方法: 在远程系统上, /etc/environment 加入以下两行,重新登陆即可. LANG=en ...
- c# 1-2+3-4.....求和
找规律: 下界:1 上界:n class Program { static void Main(string[] args) { ; ; i <=; i++) { ==) { sum -= i; ...
- MongoDB复制集成员及状态转换
此文已由作者温正湖授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 复制集(Replica Set)是MongoDB核心组件,相比早期版本采用的主从(Master-Slave) ...