`

Java深入学习之死锁

阅读更多
    最近在研究Java并发,学习死锁时偶然发现了一种嵌套管程锁死,所以自己实现了下,可能在不小心中就会犯这种错误。

1、死锁实现
    死锁原理很简单,就是线程1先获取锁A,在获取锁B;而线程2先获取锁B,在获取锁A,由于两个线程获取顺序不一样,都没有将各自的锁释放,所以就出现了死锁。代码实现也很简单:
public class DeathLock implements Runnable{
	
	private boolean flag = true;
	
	private Object o1 = new Object();
	
	private Object o2 = new Object();

	/* (non-Javadoc)
	 * @see java.lang.Runnable#run()
	 */
	public void run() {
		if (flag) {
        System.out.println(Thread.currentThread().getName()+ " 输入为:" + flag);
			flag = false;
			synchronized (o1) {
				try {
					Thread.sleep(2000);
					synchronized (o2) {
						System.out.println(Thread.currentThread().getName()+ " 我是真的");
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		} else {
			System.out.println(Thread.currentThread().getName()+ " 输入为:" + flag);
			synchronized (o2) {
				try {
					Thread.sleep(1000);
					synchronized (o1) {
						System.out.println(Thread.currentThread().getName()+ " 我是假的");
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public static void main(String[] args) {
		
		DeathLock lock1 = new DeathLock();
		Thread th1 = new Thread(lock1);
		Thread th2 = new Thread(lock1);
		th1.start();
		th2.start();
	}
}

简单运行下,
Thread-0 输入为:true
Thread-1 输入为:false
然后都停留在获取第二个锁的阶段,从而照成死锁,解决死锁也很简单,要么保持获取锁的顺序一致,要么就是保证获取锁时,没有其他线程占有锁,或者用JDK1.5后提供的Lock实现都可以,比如tryLock等方法,获取之前先判断下。

当然还有就是将对象锁Object用static修饰,测试的时候无论new多少个实例,都会造成死锁。

2、嵌套管程锁死
前几天再并发编程网上发现,然后自己实现了一下,这种情况不容易制造,也比较难于重现。其照成的原因是:线程1获取了A和B锁,然后释放B锁,等待线程2发过来的信号,然后释放A锁;线程2必须同时获取A锁和B锁,才能向线程1发送信号,这样就会照成锁死。代码实现也不复杂,就在上述代码中添加一个lock和unlock方法,run方法进行修改下:

	public void lock() {
		synchronized (o1) {
			while (!flag) {
				try {
					Thread.sleep(200);
					synchronized (o2) {
						o2.wait();
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			flag = false;
		}
	}
	
	public void unlock() {
		synchronized (o1) {
			try {
				Thread.sleep(200);
				flag = true;
				synchronized (o2) {
					o2.notify();
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public void run(){
		lock();
		try {
			System.out.println(Thread.currentThread().getName() + " : 我获得了锁");
		} finally {
			System.out.println(Thread.currentThread().getName() + " : 我将要释放锁");
			unlock();
			System.out.println(Thread.currentThread().getName() + " : 我释放了锁");
		}
	}

这是一段简单的lock实现,原理类似java新增concurrent包的Lock类
执行结果为:
Thread-0 : 我获得了锁
Thread-0 : 我将要释放锁
由此可以看出,线程Thread-0 在执行unlock时就锁死了,因为lock的o1锁没有进行释放,而unlock又需要获取o1锁,那么就照成死锁了。
当然,由于测试时都是用的同一个实例,没有释放当然或照成锁死了。确实,如果是对两个不同的实例进行测试,就不会出现这种情形,当然也就不会有线程安全问题了。
总之,不管什么形式的死锁,造成的原因就是就是因为同一个锁没有被正确的释放时,其他线程希望获取改锁,当然,在JDK1.5之后,提供的Lock类就提供了避免这种情况的方式,使用起来非常方便。
分享到:
评论

相关推荐

    操作系统之银行家算法:从原理到实现的死锁避免教程

    本资源适合操作系统学习者和考生使用,帮助他们深入理解和掌握银行家算法的原理和实现,提高操作系统的能力和水平。 提供了多种死锁检测和模拟的功能,如输入和输出系统的资源分配表,判断系统的状态是否安全,模拟...

    Java开发详解.zip

    000000_【课程介绍 —— 写在前面的话】_Java学习概述笔记.pdf 010101_【第1章:JAVA概述及开发环境搭建】_JAVA发展概述笔记.pdf 010102_【第1章:JAVA概述及开发环境搭建】_Java开发环境搭建笔记.pdf 010201_【第2...

    java面试笔试资料包括JAVA基础核心知识点深度学习Spring面试题等资料合集.zip

    java面试笔试资料包括JAVA基础核心知识点深度学习Spring面试题等资料合集: JAVA核心知识点整理-282页 Java与哈希算法.docx Java中Lambda表达式的使用.docx JAVA多线程之线程间的通信方式.docx Java注解详解.docx ...

    JAVA基础课程讲义

    第一个简单的IO流程序及深入(将文件中的数据读入) 146 Java中流的概念细分 148 Java中IO流类的体系 149 四个IO基本抽象类 150 InputStream 150 OutputStream 150 常用InputStream和OutputStream子类用法 150 ...

    java 编程入门思考

    2. Java的学习 3. 目标 4. 联机文档 5. 章节 6. 练习 7. 多媒体CD-ROM 8. 源代码 9. 编码样式 10. Java版本 11. 课程和培训 12. 错误 13. 封面设计 14. 致谢 第1章 对象入门 1.1 抽象的进步 1.2 对象的接口 1.3 ...

    java并发编程理论基础精讲

    通过深入学习,您将建立坚实的并发编程基础,能够更好地理解和应对多线程编程中的挑战。 并发编程概述: 引入并发编程的基本概念,解释为什么多线程编程在现代应用中至关重要。 线程和进程: 解释线程和进程的区别,...

    Java初学者入门教学

    2. Java的学习 3. 目标 4. 联机文档 5. 章节 6. 练习 7. 多媒体CD-ROM 8. 源代码 9. 编码样式 10. Java版本 11. 课程和培训 12. 错误 13. 封面设计 14. 致谢 第1章 对象入门 1.1 抽象的进步 1.2 对象的接口 1.3 ...

    java联想(中文)

    2. Java的学习 3. 目标 4. 联机文档 5. 章节 6. 练习 7. 多媒体CD-ROM 8. 源代码 9. 编码样式 10. Java版本 11. 课程和培训 12. 错误 13. 封面设计 14. 致谢 第1章 对象入门 1.1 抽象的进步 1.2 对象的接口 1.3 ...

    疯狂JAVA讲义

    学生提问:老师,我想学习Java编程,到底是学习Eclipse好呢,还是学习JBuilder好呢? 21 1.9 本章小结 22 本章练习 22 第2章 理解面向对象 23 2.1 面向对象 24 2.1.1 结构化程序设计简介 24 2.1.2 程序的三种...

    JAVA_Thinking in Java

    2. Java的学习 3. 目标 4. 联机文档 5. 章节 6. 练习 7. 多媒体CD-ROM 8. 源代码 9. 编码样式 10. Java版本 11. 课程和培训 12. 错误 13. 封面设计 14. 致谢 第1章 对象入门 1.1 抽象的进步 1.2 对象的接口 1.3 ...

    Thinking in Java简体中文(全)

    2. Java的学习 3. 目标 4. 联机文档 5. 章节 6. 练习 7. 多媒体CD-ROM 8. 源代码 9. 编码样式 10. Java版本 11. 课程和培训 12. 错误 13. 封面设计 14. 致谢 第1章 对象入门 1.1 抽象的进步 1.2 对象的接口 1.3 ...

    Thinking in Java 中文第四版+习题答案

    2. Java的学习 3. 目标 4. 联机文档 5. 章节 6. 练习 7. 多媒体 8. 源代码 9. 编码样式 10. Java版本 11. 课程和培训 12. 错误 13. 封面设计 14. 致谢 第1章 对象入门 1.1 抽象的进步 1.2 对象的接口 1.3 实现方案的...

    龙果java并发编程完整视频

    第4节学习并发的四个阶段并推荐学习并发的资料 [免费观看] 00:09:13分钟 | 第5节线程的状态以及各状态之间的转换详解00:21:56分钟 | 第6节线程的初始化,中断以及其源码讲解00:21:26分钟 | 第7节多种创建线程的...

    JAVA_Thinking in Java(中文版 由yyc,spirit整理).chm

    2. Java的学习 3. 目标 4. 联机文档 5. 章节 6. 练习 7. 多媒体CD-ROM 8. 源代码 9. 编码样式 10. Java版本 11. 课程和培训 12. 错误 13. 封面设计 14. 致谢 第1章 对象入门 1.1 抽象的进步 1.2 对象的接口 1.3 ...

    龙果 java并发编程原理实战

    第4节学习并发的四个阶段并推荐学习并发的资料 [免费观看] 00:09:13分钟 | 第5节线程的状态以及各状态之间的转换详解00:21:56分钟 | 第6节线程的初始化,中断以及其源码讲解00:21:26分钟 | 第7节多种创建线程的...

    Think in Java(中文版)chm格式

    2. Java的学习 3. 目标 4. 联机文档 5. 章节 6. 练习 7. 多媒体CD-ROM 8. 源代码 9. 编码样式 10. Java版本 11. 课程和培训 12. 错误 13. 封面设计 14. 致谢 第1章 对象入门 1.1 抽象的进步 1.2 ...

    Thinking in Java(中文版 由yyc,spirit整理).chm

    2. Java的学习 3. 目标 4. 联机文档 5. 章节 6. 练习 7. 多媒体CD-ROM 8. 源代码 9. 编码样式 10. Java版本 11. 课程和培训 12. 错误 13. 封面设计 14. 致谢 第1章 对象入门 1.1 抽象的进步 1.2 对象的接口 1.3 ...

    java必学必会之线程(2)

    本文对java线程进行深入学习,重点介绍了线程同步问题、线程死锁问题,感兴趣的小伙伴们可以参考一下

    Java 并发编程原理与实战视频

    第4节学习并发的四个阶段并推荐学习并发的资料 [免费观看] 00:09:13分钟 | 第5节线程的状态以及各状态之间的转换详解00:21:56分钟 | 第6节线程的初始化,中断以及其源码讲解00:21:26分钟 | 第7节多种创建线程的...

Global site tag (gtag.js) - Google Analytics