zoukankan      html  css  js  c++  java
  • 线程执行synchronized同步代码块时再次重入该锁过程中抛异常,是否会释放锁

     一个线程执行synchronized同步代码时,再次重入该锁过程中,如果抛出异常,会释放锁吗?

    如果锁的计数器为1,抛出异常,会直接释放锁;

    那如果锁的计数器为2,抛出异常,会直接释放锁吗?

    来简单测试一下

    @Slf4j
    public class SynchronizedExceptionRunnable implements Runnable {
    
        private volatile boolean flag = true;
    
        @Override
        public void run() {
            synchronized (this) {
                if (flag) {
                    //让先启动的线程先执行异常方法methodB后,flag==false,并且抛出异常线程停止,直接释放锁,不会执行后面的代码;
                    methodB();
                } else {
                    //后启动的线程再获取锁,进入if-else,再获取锁执行methodA
                    methodA();
                }
                log.info("{}:if-else end!",Thread.currentThread().getName());
            }
        }
    
        public synchronized void methodA(){
            log.info("ThreadName:{}----methodA", Thread.currentThread().getName());
        }
    
        public synchronized void  methodB() {
            flag = false;
            log.warn("ThreadName:{}----methodB will throw a exception!",Thread.currentThread().getName());
    
            //如果把下面这行抛异常的代码注释掉,会执行下面的线程睡眠5秒和最后的日志代码
            //如果不注释,会抛出异常,不在执行后面的代码,并且释放锁,methodA方法就会执行
            int a = 1/0;
    
    
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("ThreadName:{}----methodB End!",Thread.currentThread().getName());
        }
    }

    启动类

    public class Main {
        public static void main(String[] args) {
            SynchronizedExceptionRunnable runnable = new SynchronizedExceptionRunnable();
    
            Thread thread1 = new Thread(runnable,"杯子");
            Thread thread2 = new Thread(runnable,"人");
            thread1.start();
            thread2.start();
        }
    }

    执行结果如下图:

    结果分析

    当“杯子”线程获取到锁,锁的计数器为1,因为哨兵flag的原因,先获取到锁的线程调用方法methodB,会再次获取锁(因为synchronized是可重入锁),此时锁的计数器为2,然后执行methodB,该方法会抛出异常,锁的计数器直接置为0,直接释放锁;

    然后“人”线程获取到锁,锁的计数器为1,由于flag在methodB中被设置为false,调用没有异常的methodA,会再次获取锁,此时锁的计数器为2,执行完methodA,锁的计数器-1,此时锁的计数器为1,再执行完run方法中的if-else,打印日志,最后释放锁。

    如果不抛异常,是什么情况呢?我们把抛异常的代码int a = 1/0 注释掉。执行结果如下:

    这个结果大家肯定清楚,就不在赘述。

     

    总结

    所以如果锁的计数器为2,执行过程中抛出异常,锁的计数器直接置为0,会直接释放锁!

    应该是一个线程,如果执行同步代码块过程中抛出异常未捕获,会立即终止,退出同步代码块,并且释放锁,不会执行后续代码。

    最核心的就是抛了异常,线程内部如果没处理,线程会直接停止!

  • 相关阅读:
    C++编程开发学习的50条建议(转)
    编程思想:我现在是这样编程的(转)
    Linux系统编程@多线程与多进程GDB调试
    字符串分割函数 STRTOK & STRTOK_R (转)
    C语言指针与数组的定义与声明易错分析
    C语言 a和&a的区别
    C语言二重指针与malloc
    【C语言入门】C语言的组成结构(基础完整篇)!
    程序员吐槽女友败家:开酒店必须400元起步,工资却不到自己的一半!
    怎样才能和编程语言对上眼?你需要做些准备以及...
  • 原文地址:https://www.cnblogs.com/theRhyme/p/10078402.html
Copyright © 2011-2022 走看看