Java:多线程死锁

限于喜欢 提交于 2020-11-21 15:17:55

    死锁: 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。

    产生死锁的原因:

    1.因为系统资源不足。

    2.进程运行推进的顺序不合适。    

    3.资源分配不当。

    产生死锁的条件:

  1. 互斥条件:所谓互斥就是进程在某一时间内独占资源。

  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

  3. 不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。

  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

    简单的来说:死锁就是因为多线程在访问对象的时候,A线程占用了对象object1,又想去占用对象object2,但是此时的object2对象已经被B线程占用,并且B线程又想去占用object2。两个线程同时占用对方想要的对象,但是又不释放自己占有的对象,两个线程互相等待,造成拥塞无法执行下去。

    

public class LockDemo implements Runnable
{
    private static Object object1 = new Object();
    
    private static Object object2 = new Object();
    
    private int flag = 0;
    
    public static void main(String[] args)
    {
        LockDemo run0 = new LockDemo();
        LockDemo run1 = new LockDemo();
        run0.flag = 1;
        run1.flag = 2;
        Thread thread1 = new Thread(run0);
        Thread thread2 = new Thread(run1);
        thread1.start();
        thread2.start();
    }
    
    @Override
    public void run()
    {
        System.out.println(flag);
        if (flag == 1)
        {
            synchronized (object1)
            {
                System.out.println("线程 : " + flag + "锁定obj1,休息0.5秒后锁定obj2去!");
                try
                {
                    Thread.sleep(500);
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
                synchronized (object2)
                {
                    System.out.println("线程 : " + flag + "访问 object2");
                }
            }
        }
        if (flag == 2)
        {
            synchronized (object2)
            {
                System.out.println("线程 : " + flag + "锁定obj2,休息0.5秒后锁定obj1去!");
                try
                {
                    Thread.sleep(500);
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
                synchronized (object1)
                {
                    System.out.println("线程 : " + flag + "访问object1");
                }
            }
        }
        
    }
    
}

执行结果

1
2
线程 : 2锁定obj2,休息0.5秒后锁定obj1去!
线程 : 1锁定obj1,休息0.5秒后锁定obj2去!

    从执行的结果我们发现,每个线程都没有执行

System.out.println("线程 : " + flag + "访问object");

    因为线程1执行代码时把object1的时候加锁,然后去访问object2,但是此时的object2已经被线程2加上了锁,线程1和线程2分别占用object1和object2,又想去访问对方的占用的对象,显然是不可行的。就好比两个小孩交换玩具,一个小孩说:你先把玩具给我,我再把玩具给你,另外一个小孩说:不行,你要先把你的玩具给我,我再给你。结果两个小孩谁也不愿给谁,自然而然地在那僵持着。

    在代码中在修饰object对象的时候,使用了static关键字,如果不使用static 关键字的执行结果是什么样的呢?

1
线程 : 1锁定obj1,休息0.5秒后锁定obj2去!
2
线程 : 2锁定obj2,休息0.5秒后锁定obj1去!
线程 : 2访问object1
线程 : 1访问 object2

    可以看到并没有发生死锁,为什么?是因为使用static 关键字的时,两个object是公共的,不使用关键字时,两个object是线程自己用了两个独立的对象。同样我们打个比方,使用static关键修饰的object对象,就好比幼儿园中共有的两个玩具,大家谁都可以玩,但是每个小孩,都只能同时拥有一个。一个小朋友要是想要玩另外一个小朋友的玩具,必须要俩人互相交换。不用static关键字修饰的object对象,就好比每个小朋友自己带玩具来玩,不是共有的,我想玩哪个就玩哪个。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!