zoukankan      html  css  js  c++  java
  • Java多线程(五):死锁

    死锁

    概念

    当线程Thread-0持有锁Lock1,Thread-1持有锁Lock2,此时Thread-0申请Lock2锁的使用权,Thread-1申请Lock1锁的使用权,Thread-0和Thread-1都在无限地等待锁的使用权。这样就造成了死锁。

    死锁是主要由于设计的问题。一旦出现死锁,死锁的线程就会永远不能使用,同步方法不会被执行,死锁线程不会被自动终止,无尽地消耗CPU资源。

    例子

    看一个例子
    ThreadDomain29类,模拟图片中,线程持有一个锁,申请被其他线程持有的锁的情况

    public class ThreadDomain29 {
        private final Object obj1 = new Object();
        private final Object obj2 = new Object();
    
        public void obj1obj2() throws Exception
        {
            synchronized (obj1)
            {
                Thread.sleep(2000);
                synchronized (obj2)
                {
                    System.out.println("obj1obj2 end!");
                }
            }
        }
    
        public void obj2obj1() throws Exception
        {
            synchronized (obj2)
            {
                Thread.sleep(2000);
                synchronized (obj1)
                {
                    System.out.println("obj2obj1 end!");
                }
            }
        }
    }
    

    MyThread29_0类

    public class MyThread29_0 extends Thread{
        private ThreadDomain29 dl;
    
        public MyThread29_0(ThreadDomain29 dl)
        {
            this.dl = dl;
        }
    
        public void run()
        {
            try
            {
                dl.obj1obj2();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }
    

    MyThread29_1类

    public class MyThread29_1 extends Thread{
        private ThreadDomain29 dl;
    
        public MyThread29_1(ThreadDomain29 dl)
        {
            this.dl = dl;
        }
    
        public void run()
        {
            try
            {
                dl.obj2obj1();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }
    

    main方法

    public class MyThread29_main {
        public static void main(String[] args)
        {
            ThreadDomain29 dl = new ThreadDomain29();
            MyThread29_0 t0 = new MyThread29_0(dl);
            MyThread29_1 t1 = new MyThread29_1(dl);
            t0.start();
            t1.start();
    
            while(true);
        }
    }
    

    因为发生了死锁,所以你不会看到任何结果。

    死锁排查

    jps+jstack

    jps找到进程id

    jstack打印堆栈
    输入jstack 10208

    可以看到,找到了两个死锁。

    JConsole

    命令行输入JConsole

    点击“检测死锁”

    已经检测到了死锁

    Java Visual VM

    命令行输入jvisualvm
    找到我们的进程

    自动检测到死锁,推荐使用这种方式

    死锁避免

    1.尽量少用嵌套的锁。
    2.如果一定要用嵌套锁,那么请规定好获取锁的顺序。例子如下:

    //伪代码
    //condition1可以是属性值大小,hash值大小的比较等等
    if(condition1){
                synchronized (obj2)
                {
                    Thread.sleep(2000);
                    synchronized (obj1)
                    {
                        System.out.println("obj2obj1 end!");
                    }
                }
            }else{
                synchronized (obj1)
                {
                    Thread.sleep(2000);
                    synchronized (obj2)
                    {
                        System.out.println("obj1obj2 end!");
                    }
                }
            }
    

    3.使用Lock的tryLock方法,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。
    后面讲到ReentrantLock会详细分析。

  • 相关阅读:
    js常用工具函数
    vue-cli跨域问题解决
    charles抓包404问题(左侧不显示配置)
    vuex存储与本地储存(localstorage、sessionstorage)的区别(笔记)
    借助axios的拦截器实现Vue.js中登陆状态校验的思路(笔记)
    cornerstone使用注意点
    本地仓库连接远程仓库,git本地新建项目上传到远程git仓库上正确流程
    做一个不那么差的程序员
    解决 php Call to undefined function shm_attach()
    Redis 常用的数据结构
  • 原文地址:https://www.cnblogs.com/Java-Starter/p/11152705.html
Copyright © 2011-2022 走看看