zoukankan      html  css  js  c++  java
  • Java线程——线程之间的死锁

    一,什么是死锁?

      所谓的死锁是指多个线程因为竞争资源而造成的一种僵局(相互等待),若无外力的作用,这些进程都不能向前推进。

    二,死锁产生的条件?

      (1)互斥条件:线程要求对所分配的资源(如打印机)进行排他性控制,既在某一段时间内,资源只能被一个线程所占有。

      (2)不剥夺条件:线程所获得的资源在未使用完前,不能被其他的线程强行夺走,只能由该线程自己释放。

      (3)请求和保持的条件:线程已经保持了一个 资源,但又提出了新的资源请求,而该资源被其他的线程所占用,此时请求进程被阻塞,但对自己的资源也不会释放。

      (4)循环等待条件:存在一种线程资源的循环等待链,链中的每一个线程已获得的资源同时被链中下一个线程所请求。

    三,产生死锁的一个例子

    package com.itheima.gan;
    /**
     * 一个简单的死锁类
     * @author 12428
     * 当DeadLock类的对象flag==1时,(td1)先锁定o1,睡眠500毫秒
     * 在td1睡眠的时候,另一个类对象的flag==0,(td2)线程启动,先锁定o2,睡眠500毫秒
     * 静态属性是类的所有对象所共有的。
     * 在td1睡眠结束的时候需要锁定o2才能继续执行,而此o2已被td2锁定
     * td2 睡眠结束后需要锁定 o1 才能继续执行,而此时 o1 已被 td1 锁定; 
     * td1、td2 相互等待,都需要得到对方锁定的资源才能继续执行,从而死锁。
     *
     */
    public class DeadLock implements Runnable{
        
        public int flag=1;
        
        //静态对象是类的所有对象共享的
        private static Object o1=new Object(),o2=new Object();
        
        @Override
        public void run() {
            System.out.println("flag = "+flag);
            
            if(flag==1) {
                synchronized(o1) {
                    
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    
                    synchronized (o2) {
                        System.err.println("2");
                    }
                }
            }
            
            if(flag==0) {
                synchronized (o2) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    
                    synchronized (o1) {
                        System.out.println("3");
                    }
                }
            }
        }
    
        public static void main(String[] args) {
            DeadLock td1=new DeadLock();
            DeadLock td2=new DeadLock();
            
            td1.flag=1;
            td2.flag=0;
            
            //td1,td2都处于可执行的状态,但虚拟机调用那个线程是未知的
            new Thread(td1).start();
            new Thread(td2).start();
        }
    }

    四,处理死锁的方法

    (1)加锁的顺序(线程按照一定的顺序来加锁)

    package com.itheima.gan;
    /*
     * 如何避免死锁
     * 加锁的顺序
     */
    public class DeadLock2 {
        public int flag=1;
        //静态对象是类的所有对象共享的 
        private static Object o1=new Object(), o2=new Object();
        
        public void money(int flag) {
            
            this.flag=flag;
            
            if(flag==1) {
                synchronized(o1) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized(o2) {
                        System.out.println("当前线程是"+Thread.currentThread().getName()+
                                " "+" flag的值是 :"+flag);
                    }
                }
            }
            
            if(flag==0) {
                synchronized(o2) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized(o1) {
                        System.out.println("当前线程是"+Thread.currentThread().getName()+
                                " "+" flag的值是 :"+flag);
                    }
                }
            }
        }
        
        
        public static void main(String[] args) {
            final DeadLock2 td1=new DeadLock2();
            final DeadLock2 td2=new DeadLock2();
            
            td1.flag=1;
            td2.flag=0;
            
            final Thread t1=new Thread(new Runnable() {
                @Override
                public void run() {
                    td1.flag=1;
                    td1.money(1);
                    
                }
            });
            t1.start();
            
            Thread t2=new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        //核心代码,让线程2在线程1执行完在执行,下面join方法的作用是当前线程放弃cpu的执行权,返回到t1线程执行的地方,直到t1线程执行完,再继续向下执行。
                        t1.join();
                    }catch (Exception e) {
                        e.printStackTrace();
                    }
                    
                    td2.flag=0;
                    //调用方法
                    td2.money(0);
                }
            });
            
            t2.start();
        }
    }
  • 相关阅读:
    四、面向对象分析和设计全流程概述
    三、三大核心特征-继承
    二、三大核心特征-多态
    [第三章]一、三大核心特征-封装
    四、抽象类
    三、接口
    二、对象
    [第二章]一、类
    六、面向对象的迷思
    五、面向对象的应用范围
  • 原文地址:https://www.cnblogs.com/zhilili/p/11983784.html
Copyright © 2011-2022 走看看