• 线程死锁


    定义:死锁是指两个或者两个以上的线程在执行过程中,因争夺资源而造成的相互等待的现象。

    死锁产生的四个条件:

    互斥条件:指线程对已经获取到的资源进行排它性使用,即该资源同时只由一个线程占用。如果此时还有其他线程请求获取该资源,则请求者只能等待,直至占有资源的线程释放该资源。

    持有并请求条件:指一个线程已经持有了至少一个资源,但又提出了新的资源请求,而新资源已被其他线程占有,所以当前线程会被阻塞,但阻塞的同时并不释放自己已经获取的资源。

    不可剥夺条件:指线程获取到的资源在自己使用完之前不能被其他线程抢占,只有在自己使用完毕后才由自己释放该资源。

    环路等待条件:指在发生死锁时,必然存在一个线程—资源的环形链,即线程集合{T0, T1, T2, …, Tn}中的T0正在等待一个T1占用的资源,T1正在等待T2占用的资源,……Tn正在等待已被T0占用的资源。

    死锁例子:

    public class DeadLock {
        private static Object resourceA = new Object();
        private static Object resourceB = new Object();
    
        public static void main(String[] args) {
            Thread threadA = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (resourceA){
                        System.out.println(Thread.currentThread() + "get resourceA!");
                        try {
                            Thread.sleep(1000);
                        }catch (InterruptedException exception){
                            exception.printStackTrace();;
                        }
                        System.out.println(Thread.currentThread() + "waiting get resourceB!");
                        synchronized (resourceB){
                            System.out.println(Thread.currentThread() + "get resourceB!");
                        }
                    }
                }
            });
            Thread threadB = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (resourceB){
                        System.out.println(Thread.currentThread() + "get resourceB!");
                        try {
                            Thread.sleep(1000);
                        }catch (InterruptedException exception){
                            exception.printStackTrace();;
                        }
                        System.out.println(Thread.currentThread() + "waiting get resourceA!");
                        synchronized (resourceA){
                            System.out.println(Thread.currentThread() + "get resourceA!");
                        }
                    }
                }
            });
    
            threadA.start();
            threadB.start();
    
        }
    }

    输出:

    分析:本例是如何满足死锁的四个条件的。

    首先,resourceA和resourceB都是互斥资源,当线程A调用synchronized(resourceA)方法获取到resourceA上的监视器锁并释放前,线程B再调用synchronized(resourceA)方法尝试获取该资源会被阻塞,只有线程A主动释放该锁,线程B才能获得,这满足了资源互斥条件

    线程A首先通过synchronized(resourceA)方法获取到resourceA上的监视器锁资源,然后通过synchronized(resourceB)方法等待获取resourceB上的监视器锁资源,这就构成了持有并请求条件

    线程A在获取resourceA上的监视器锁资源后,该资源不会被线程B掠夺走,只有线程A自己主动释放resourceA资源时,它才会放弃对该资源的持有权,这构成了资源的不可剥夺条件

    线程A持有objectA资源并等待获取objectB资源,而线程B持有objectB资源并等待objectA资源,这构成了环路等待条件。所以线程A和线程B就进入了死锁状态。

    避免线程

    避免死锁,只需要破坏掉至少一个构造死锁的必要条件即可,但是,目前只有持有并请求和环路等待条件是可以被破坏的。

    1.破坏环路等待条件

    public class DeadLock{
        private static Object resourceA = new Object();
        private static Object resourceB = new Object();
    
        public static void main(String[] args) {
            Thread threadA = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (resourceA){
                        System.out.println(Thread.currentThread() + "get resourceA!");
                        try {
                            Thread.sleep(1000);
                        }catch (InterruptedException exception){
                            exception.printStackTrace();;
                        }
                        System.out.println(Thread.currentThread() + "waiting get resourceB!");
                        synchronized (resourceB){
                            System.out.println(Thread.currentThread() + "get resourceB!");
                        }
                    }
                }
            });
            Thread threadB = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (resourceA){
                        System.out.println(Thread.currentThread() + "get resourceB!");
                        try {
                            Thread.sleep(1000);
                        }catch (InterruptedException exception){
                            exception.printStackTrace();;
                        }
                        System.out.println(Thread.currentThread() + "waiting get resourceA!");
                        synchronized (resourceB){
                            System.out.println(Thread.currentThread() + "get resourceA!");
                        }
                    }
                }
            });
    
            threadA.start();
            threadB.start();
    
        }
    }

    输出:

    2.破坏持有并请求条件

    public class DeadLockTest2 {
        private static Object resourceA = new Object();
        private static Object resourceB = new Object();
    
        public static void main(String[] args) {
            Thread threadA = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (resourceA){
                        System.out.println(Thread.currentThread() + "get resourceA!");
                        try {
                            resourceA.wait(1000);
                        }catch (InterruptedException exception){
                            exception.printStackTrace();;
                        }
                        System.out.println(Thread.currentThread() + "waiting get resourceB!");
                        synchronized (resourceB){
                            System.out.println(Thread.currentThread() + "get resourceB!");
                        }
                    }
                }
            });
            Thread threadB = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (resourceB){
                        System.out.println(Thread.currentThread() + "get resourceB!");
                        try {
                            resourceB.wait(1000);
                        }catch (InterruptedException exception){
                            exception.printStackTrace();;
                        }
                        System.out.println(Thread.currentThread() + "waiting get resourceA!");
                        synchronized (resourceA){
                            System.out.println(Thread.currentThread() + "get resourceA!");
                        }
                    }
                }
            });
    
            threadA.start();
            threadB.start();
    
        }
    }

    注意:不推荐使用,wait()时间太长,就会浪费资源,太短则可能不能够避免死锁!

    参考:<<Java 并发编程之美>>

  • 相关阅读:
    css下背景渐变与底部固定的蓝天白云
    indy10中idtcpclient的使用问题[和大华电子称数据交换]
    cliendataset中自增长字段的处理
    和大华电子称进行对数据通讯
    cxgrid主从表的困惑
    基于xml基类的web查询
    关于屏幕文件
    基于xml文件查询的xml文件之生成篇
    关于400改程序
    Tapestry Spring Hibernate整合工作小结[摘]
  • 原文地址:https://www.cnblogs.com/iuyy/p/13516547.html
Copyright © 2020-2023  润新知