最近在研究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多线程编程是开发高并发应用的关键技术之一,但随之而来的问题也十分复杂,比如死锁。死锁是指两个或多个线程在执行过程中,因争夺资源而...通过深入学习并实践这些知识,可以提升你在Java并发编程领域的专业能力。
在Java编程中,死锁和生产者消费者问题是多线程编程中的两个重要...通过分析`ThreadDeadLock.java`和`ProducerConsumer.java`的源码,我们可以深入理解这两个概念,并从中学习如何在实际项目中避免和解决类似的问题。
Java编程语言以其强大的功能和...通过阅读"说明.txt"和"房门终于被打开了(解决死锁的方法)"这两个文件,我们可以更深入地理解死锁的本质,学习如何在实际项目中避免和解决死锁,从而提高多线程程序的健壮性和效率。
总的来说,通过银行家算法的模拟实现,我们可以深入理解死锁避免机制,学习如何在多线程环境中合理分配和管理资源,以及如何预防和解决潜在的死锁问题。这对于提升软件系统的可靠性具有重要意义。
《深入学习:Java多线程编程》是一本专注于Java并发技术的专业书籍,旨在帮助开发者深入理解和熟练运用Java中的多线程编程。Java多线程是Java编程中的核心部分,尤其在现代高性能应用和分布式系统中不可或缺。理解并...
同时,通过学习和使用JCarder,开发者也能更深入地理解Java多线程编程中的并发控制和死锁预防策略,提升自身的技能水平。 总结来说,JCarder是一款针对Java多线程程序的死锁检测工具,它通过JMX接口提供实时监控,...
在Java编程中,死锁是并发编程中一...通过上述讲解和提供的源代码实例,你可以深入了解Java中死锁的原理,并学习如何避免和解决这一问题。在实际编程中,理解并熟练应用这些策略对于编写高效、稳定的并发程序至关重要。
可以通过阅读《Java并发编程实战》等书籍,以及在线博客如文章链接中提到的(https://caoyaojun1988-163-com.iteye.com/blog/1697395)来深入学习。 通过以上内容,我们可以了解到dump线程在分析和解决Java中的死锁...
"Java深入学习"的主题涵盖了从基础到高级的各种Java技术,包括语法、类库、框架以及最佳实践。下面将对Java的一些核心概念和重要知识点进行详细介绍。 1. **Java语法基础**:Java的语法基于C++,但更为简洁。它包括...
"Java超强学习笔记"显然是一份全面且深入的Java学习资料,由一位极具洞察力和组织能力的作者精心编纂。这份笔记可能包含了从基础知识到高级特性的全方位讲解,旨在帮助学习者构建坚实的Java编程基础,并提升他们的...
"面向对象之封装,继承,多态(上).docx"则深入到Java的核心特性——面向对象编程。你将学习到如何创建类、对象,理解封装、继承和多态的概念,这是理解Java和其他面向对象语言的关键。 在"19.EL表达式和JSTL.docx...
Java同步机制是多线程编程中确保数据一致性与正确性的关键。在Java中,主要有两种同步机制:内置的`synchronized`关键字以及基于`...通过深入学习这些机制,开发者可以更好地处理并发问题,提高程序的性能和稳定性。
《深入浅出Java》这本书以其独特的讲解方式,旨在让学习者轻松掌握复杂的Java编程...通过学习,你将能够编写出高效、可靠的Java应用程序,并且为未来深入学习Java EE、Android开发或其他Java相关的技术打下坚实基础。
本学习总结将深入探讨并发容器、同步容器、同步工具、死锁、异常处理、线程中断、线程池、返回结果以及同步方法等核心概念。 1. **并发容器**:Java提供了一系列的并发容器,如`ConcurrentHashMap`,它在并发环境下...
在深入学习时,你会遇到Java集合框架,它包括数组列表、链表、队列、栈、映射等数据结构。这些集合工具能帮助你有效地存储和管理数据。特别是HashMap和ArrayList,它们在实际开发中有着广泛的应用。 异常处理是Java...
在“中科大软件学院java学习资料”中,涵盖了Java语言的基础到进阶知识,非常适合初学者和有一定经验的开发者进行深入学习。 1. **Java基础知识** - **1_1 Introduction to Java**: 这部分内容可能涵盖Java的历史...
"JAVA解惑"可能会对这些概念进行深入浅出的解析,以帮助初学者更好地理解和运用。 2. **语法问题**:Java的语法相对严谨,初学者在编写代码时常常会遇到语法错误。例如,分号遗漏、括号不匹配、类型转换错误等。这...
Java基础学习笔记全集涵盖了广泛的Java编程概念,是学习和准备Java相关笔试的理想资源。这份资料集合了J2EE框架、MVC模式、线程管理、...通过深入学习和实践,可以提升Java编程技能,并为解决实际问题打下坚实基础。
本压缩包提供了全面的Java学习资料,涵盖了从基础到高级的多个主题,帮助初学者和进阶者深入理解和掌握Java技术。 首先,我们有《全新java基础实践教程》。这本书详细介绍了Java的基础知识,包括语法、变量、数据...
Java多线程是Java编程中的核心概念,尤其在如今并发性能至关重要的软件开发中,它的重要性不言而喻。...深入学习这一部分将极大地提升Java程序员的设计能力和解决问题的能力,使得能够编写出更加健壮、高效的并发程序。