zoukankan      html  css  js  c++  java
  • JAVA死锁的写法

    在java开发中,避免不了要加锁控制程序逻辑,但加锁有可能导致死锁,造成线程永远卡死在等待释放锁,后面的代码得不到执行; 
    在java里,一般是通过synchronized关键字加锁,在jdk1.5版本中新增了Lock接口显示的加锁,本文讨论用这两种方式实现死锁; 
    方式一:

    public static void main(String[] args) {
            Object lock1 = new Object();
            Object lock2 = new Object();
            ExecutorService service = Executors.newCachedThreadPool();
            service.execute(() ->{
                while (true){
                    synchronized (lock2){
                        synchronized (lock1){
                            System.out.println("Thread1");
                        }
                    }
                }
            });
            service.execute(() ->{
                while (true){
                    synchronized (lock1){
                        synchronized (lock2){
                            System.out.println("Thread2");
                        }
                    }
                }
            });
            service.shutdown();
        }

    上面的代码开启了两个线程,两个线程都循环打印字符串,正常来说两个线程都会不断打印,但这里出现了死锁,导致两个线程都会打印停止,逻辑分析:两个线程执行到某一时刻,线程一执行到synchronized (lock2){这一句,获得了对象lock2上的锁,线程二执行到synchronized (lock1){这一句,获得了对象lock1上的锁,接下来,线程一需要执行synchronized (lock1){这一句尝试获取lock1的锁,由于lock1的锁被线程二占用,线程一等待线程二释放lock1的锁,这时线程二需要执行synchronized (lock2){这一句,尝试获取lock2上的锁,由于lock2上的锁被线程一占用,线程二等待线程一释放lock2上的锁,这样,两个线程互相等待释放锁,导致两个线程永远无法执行后面的代码,导致死锁; 
    方式二:

    static final Lock LOCK1 = new ReentrantLock();
        static final Lock LOCK2 = new ReentrantLock();
        public static void main(String[] args) {
            ExecutorService service = Executors.newCachedThreadPool();
            service.execute(new PrintTask1(1));
            service.execute(new PrintTask2(2));
    
        }
        static class PrintTask1 implements Runnable{
            private int id = -1;
            public PrintTask1(int i){
                id = i;
            }
            @Override
            public void run() {
                while (true){
                    LOCK1.lock();
                    LOCK2.lock();
                    System.out.println("" + id);
                    LOCK2.unlock();
                    LOCK1.unlock();
                }
            }
        }
    
        static class PrintTask2 implements Runnable{
            private int id = -1;
            public PrintTask2(int i){
                id = i;
            }
            @Override
            public void run() {
                while (true){
                    LOCK2.lock();
                    LOCK1.lock();
                    System.out.println("" + id);
                    LOCK2.unlock();
                    LOCK1.unlock();
                }
            }
        }

    方式二的代码属于显示加锁,使用了jdk1.5新增的Lock接口,与方式一类似,当两个线程执行到某一时刻,线程一执行了LOCK1.lock()获得了LOCK1锁,线程二执行了LOCK2.lock()获得了LOCK2锁,接下来两个线程又要互相等待对方释放锁,导致死锁。

    哔哔叭哔哄
  • 相关阅读:
    jdk9 特性
    jdk8 特性
    Eclipse中Spring插件的安装
    C++避免程序运行完后窗口一闪而过的方法
    完全二叉树节点个数
    Shell 编写倒着的*三角形
    Drools源于规则引擎
    Spring Data MongoDB 三:基本文档查询(Query、BasicQuery
    docker环境搭建
    MyBatis根据数组、集合查询
  • 原文地址:https://www.cnblogs.com/he-px/p/7553157.html
Copyright © 2011-2022 走看看