Java线程 - 死锁(deadlock)

一、死锁

死锁是指这样一种状况。当多个线程竞争稀缺资源的时,由于他们相互等待获取对方线程所拥有的资源,大家都无法满足,从而都无法继续执行的情形。

P2进程拥有R1资源,但他正请求获取R2资源;而P1进程拥有R2资源,但他正请求R1资源。

1.1 Coffman条件--产生死锁的4个条件

如果一个系统中如下4种情形同时存在,则产生死锁情形的机会就会上升

  • 互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用
  • 等待和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放
  • 不可剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放
  • 环路等待条件:在发生死锁时,必然存在一个进程--资源的环形链。更一般性来讲会有进程集合{P1,P2,P3....Pn},P1 申请P2获取的资源,P2申请P3资源....而Pn申请P1获取的资源,这样形成了一个闭环。

这4个条件即Coffman条件,由Edward G.Coffman, Jr先生于1971年首次提出。

二、java多线程死锁探测

从JDK1.5开始java.lang.management包提供了ThreadMXBean类,该类可用获取关于线程的各种各样的信息,包括探测线程的死锁。findMonitorDeadlockedThreads()方法返回long[],这些long[]表示发生死锁的线程的id。如果long[]数组等于null则表示没有发现死锁的线程。但这个方法只是监控object monitor的死锁,对于使用java.util.concurrent包的ownable synchronizer则无能为力。为此JDK1.6引入了一个新的方法findDeadlockedThreads()除了监控object monitor死锁外,同时还监控ownable synchronizer的死锁。

通过建立一个定期任务,让它使用ThreadMXBean定期核查是否存在死锁的线程,就可以解决线程死锁探测的问题。例如:

public class ThreadDeadlockDetector {

    //建立定期任务的调度器
    private final Timer threadCheck = new Timer("ThreadDeadLockDector",true);

    private final Collection<Listener> listeners = new CopyOnWriteArraySet<Listener>();

    private final ThreadMXBean mbean = ManagementFactory.getThreadMXBean();    

    private static final int DEFAULT_DEADLOCK_CHECK_PERIOD = 10000;

    public ThreadDeadlockDetector(){
        this(DEFAULT_DEADLOCK_CHECK_PERIOD);
    }

    public ThreadDeadlockDetector(int deadlockCheckPeriod){
        //建立一个定期核查的任务
        threadCheck.schedule(new TimerTask(){
            @Override
            public void run() {
                checkForDeadlocks();
            }

        }, 10, deadlockCheckPeriod);
    }

    //一旦返现有死锁,就发出死锁报警
    private void checkForDeadlocks() {
        long[] ids = findDeadlockedThreads();
        if(ids != null && ids.length > 0) {
            Thread[] threads = new Thread[ids.length];
            for(int i=0; i<threads.length; i++){
                threads[i] = findMatchingThread(mbean.getThreadInfo(ids[i]));
            }
            fireDeadlockDetected(threads);
        }

    }

    //核查是否存在死锁
    private long[] findDeadlockedThreads(){
        if(mbean.isSynchronizerUsageSupported()){
            return mbean.findDeadlockedThreads();
        }else{
            return mbean.findMonitorDeadlockedThreads();
        }
    }

    private Thread findMatchingThread(ThreadInfo inf){
        for(Thread thread:Thread.getAllStackTraces().keySet()){
            if(thread.getId() == inf.getThreadId()){
                return thread;
            }
        }

        throw new IllegalStateException("Deadlocked Thread not found");

    }

    public boolean addListener(Listener l){
        return listeners.add(l);
    }

    public boolean removeListener(Listener l){
        return listeners.remove(l);
    }

    private void fireDeadlockDetected(Thread[] threads){
        for(Listener l : listeners){
            l.deallockDetected(threads);
        }
    }

    public interface Listener {
        void deallockDetected(Thread[] deadlockedThreads);
    }
}
时间: 2024-10-25 15:12:04

Java线程 - 死锁(deadlock)的相关文章

Java线程死锁解决方法(转)

转自:http://leowzy.iteye.com/blog/740859 Java线程死锁如何避免这一悲剧  Java线程死锁需要如何解决,这个问题一直在我们不断的使用中需要只有不断的关键.不幸的是,使用上锁会带来其他问题.让我们来看一些常见问题以及相应的解决方法: Java线程死锁 Java线程死锁是一个经典的多线程问题,因为不同的线程都在等待那些根本不可能被释放的锁,从而导致所有的工作都无法完成.假设有两个线程,分别代表两个饥饿的人,他们必须共享刀叉并轮流吃饭.他们都需要获得两个锁:共享

55行代码实现Java线程死锁

死锁是Java多线程的重要概念之一,也经常出现在各大公司的笔试面试之中.那么如何创造出一个简单的死锁情况?请看代码: class Test implements Runnable { boolean flag; Test(boolean flag) { this.flag = flag; } public void run() { if(flag) { while(true) //这里用while(true)使得线程在这里无限循环,可以避免各种随机情况造成死锁不成功 synchronized(M

Java线程死锁

Java多线程使用synchronized 锁时,可能会出现死锁:死锁会导致两个线程无限等待,致使程序异常.因此使用synchronized 关键字时注意死锁的问题. 笔者在第一次运行程序的时候属性 A="a".B="a",并没有引起死锁的问题:原因很简单,这时A 和 B的地址是一样的,synchronized 认为是同一个对象资源,不会对对象A 和 B同时加锁. 引起死锁的例子: public class DeadLock { private String A =

java 线程 死锁(哲学家用餐案例讲解) -------thinking java 4

package org.rui.thread.deadlock; /** * 死鎖 * * 筷子 * * @author lenovo * */ public class Chopstick { private boolean taken = false; public synchronized void take() throws InterruptedException { while (taken) { wait(); } taken = true; } public synchroniz

I学霸官方免费教程四十一 :Java基础教程之线程死锁

线程死锁 是指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的线程称为死锁线程. 例如:某一商店有两个人PS和PB在做交易,PS手里拿着货物对PB说,你先给我钱我在给你货,而PB拿着钱对PS说你先给我货我在给你钱.两个人就此僵持下去,永远也无法做成交易,这就构成了死锁. 实例: package thread.deadlock; /** * 创建DeadlockDe

Java笔记六.线程同步、线程死锁

线程同步.线程死锁 在上一篇文章中,有一个模拟售卖火车票系统,在卖车票的程序代码中,极有可能碰到一种意外,就是同一张票号被打印两次多次,也可能出现打印出0甚至负数的票号.具体表现为:假设tickets的值为1的时候,线程1刚执行完if(tickets>0)这行代码,正准备执行下面的代码,就在这时,操作系统将CPU切换到了线程2上执行,此时tickets的值仍为1,线程2执行完上面两行代码,tickets的值变为0后,CPU又切回到了线程1上执行,线程1不会再执行if(tickets>0)这行代

JAVA笔记14__多线程共享数据(同步)/ 线程死锁 /

/** * 多线程共享数据 * 线程同步:多个线程在同一个时间段只能有一个线程执行其指定代码,其他线程要等待此线程完成之后才可以继续执行. * 多线程共享数据的安全问题,使用同步解决. * 线程同步两种方法: * 1.同步代码块 * synchronized(要同步的对象){ 要同步的操作 } * 2.同步方法 * public synchronized void method(){ 要同步的操作 } */ public class Main { public static void main(

Java线程学习整理--3--简单的死锁例子

1.线程死锁的概念: 简单地理解下吧! 我们都知道,线程在执行的过程中是占着CPU的资源的,当多个线程都需要一个被锁住的条件才能结束的时候,死锁就产生了! 还有一个经典的死锁现象: 经典的“哲学家就餐问题”,5个哲学家吃中餐,坐在圆卓子旁.每人有5根筷子(不是5双),每两个人中间放一根,哲学家时而思考,时而进餐. 每个人都需要一双筷子才能吃到东西,吃完后将筷子放回原处继续思考,如果每个人都立刻抓住自己左边的筷子,然后等待右边的筷子空出来,同时又不 放下已经拿到的筷子,这样每个人都无法得到1双筷子

Java线程同步与死锁、生产者消费者模式以及任务调度等

一.Thread类基本信息方法 package Threadinfo; public class MyThread implements Runnable{ private boolean flag = true; private int num = 0; @Override public void run() { while(flag) { System.out.println(Thread.currentThread().getName()+"-->"+num++); } }