线程入门(四)---Synchronized可重入锁

小咪咪 2022-11-30 05:37 235阅读 0赞

synchronized 是可重入锁吗?为什么?

一、什么是可重入锁?

我们先来看一段维基百科的定义。

若一个程序或子程序可以“在任意时刻被中断然后操作系统调度执行另外一段代码,这段代码又调用了该子程序不会出错”,则称其为可重入(reentrant或re-entrant)的。即当该子程序正在运行时,执行线程可以再次进入并执行它,仍然获得符合设计时预期的结果。与多线程并发执行的线程安全不同,可重入强调对单个线程执行时重新进入同一个子程序仍然是安全的。

通俗来说:当线程请求一个由其它线程持有的对象锁时,该线程会阻塞,而当线程请求由自己持有的对象锁时,如果该锁是重入锁,请求就会成功,否则阻塞。

不同线程对同一对象锁是要竞争的,是同步阻塞模式

二、synchronized可重入锁

  1. public class Xttblog extends SuperXttblog {
  2. public static void main(String[] args) {
  3. Xttblog child = new Xttblog();//此时的对象锁child
  4. child.doSomething();//该线程获得 child 对象的锁
  5. }
  6. public synchronized void doSomething() {
  7. for(int i=0;i<3;i++){
  8. System.out.println("child.doSomething()" + Thread.currentThread().getName()+"--"+i);
  9. doAnotherThing(); // 调用自己类中其他的synchronized方法
  10. }
  11. }
  12. private synchronized void doAnotherThing() {
  13. super.doSomething(); // 调用父类的synchronized方法
  14. System.out.println("child.doAnotherThing()" + Thread.currentThread().getName());
  15. }
  16. }
  17. class SuperXttblog {
  18. public synchronized void doSomething() {
  19. System.out.println("father.doSomething()" + Thread.currentThread().getName());
  20. }
  21. }

输入结果:
在这里插入图片描述

可验证 synchronized 是可重入锁!因为这些方法输出了相同的线程名称,表明即使递归使用synchronized也没有发生死锁,证明其是可重入的。

这里的对象锁只有一个,就是 child 对象的锁,当执行 child.doSomething 时,该线程获得 child 对象的锁,在 doSomething 方法内执行 doAnotherThing 时再次请求child对象的锁,因为synchronized 是重入锁,所以可以得到该锁,继续在 doAnotherThing 里执行父类的 doSomething 方法时第三次请求 child 对象的锁,同样可得到。如果不是重入锁的话,那这后面这两次请求锁将会被一直阻塞,从而导致死锁。

所以在 java 内部,同一线程在调用自己类中其他 synchronized 方法/块或调用父类的 synchronized 方法/块都不会阻碍该线程的执行。就是说同一线程对同一个对象锁是可重入的,而且同一个线程可以获取同一把锁多次,也就是可以多次重入。

三、可重入锁的实现原理

可重入锁的原理是什么?

重入锁实现可重入性原理或机制是:每一个锁关联一个线程持有者和计数器,当计数器为 0 时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应的方法;当某一线程请求成功后,JVM会记下锁的持有线程,并且将计数器置为 1;此时其它线程请求该锁,则必须等待;而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增;当线程退出同步代码块时,计数器会递减,如果计数器为 0,则释放该锁。

参考文章:synchronized 是可重入锁吗?为什么?

发表评论

表情:
评论列表 (有 0 条评论,235人围观)

还没有评论,来说两句吧...

相关阅读

    相关 线-

    3.4 可重入锁(递归锁) 3.4.1 概念说明 是指在同一线程在外层方法获取到锁的时侯,在进入该线程的内层方法会自动获取锁(前提,锁对 象的是同一个对象),不会因为之前

    相关 Java

    一 点睛 ReentrantLock 可以指定为公平锁。 公平锁和非公平锁的区别:首先从字面意思理解,公平锁自然是遵循FIFO(先进先出)原则的,先到的线程会优先获取资