synchronized——可重入性

本文详细介绍了Java中synchronized关键字的可重入性特点及其实现原理,通过具体示例代码展示了同一线程如何能够多次获取同一把锁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、synchronized的可重入性

在java内部,同一线程在调用自己类中其他synchronized方法/块或调用父类的synchronized方法/块都不会阻碍该线程的执行,就是说同一线程对同一个对象锁是可重入的,而且同一个线程可以获取同一把锁多次,也就是可以多次重入。 因为java线程是基于“每线程(per-thread)”,而不是基于“每调用(per-invocation)”的(java中线程获得对象锁的操作是以每线程为粒度的,per-invocation互斥体获得对象锁的操作是以每调用作为粒度的)

public class Child extends Father {
    public static void main(String[] args) {
        Child child = new Child();
        child.doSomething();
    }

    public synchronized void doSomething() {
        System.out.println("child.doSomething()");
        doAnotherThing(); // 调用自己类中其他的synchronized方法

    }

    private synchronized void doAnotherThing() {
        super.doSomething(); // 调用父类的synchronized方法
        System.out.println("child.doAnotherThing()");
    }
}

class Father {
    public synchronized void doSomething() {
        System.out.println("father.doSomething()");
    }
}

运行结果:

child.doSomething()
father.doSomething()
child.doAnotherThing()

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

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

public class Child extends Father {
    public static void main(String[] args) {
        Child child = new Child();
        child.doSomething();
    }
    public void doSomething() {
        while (i > 0) {
            System.out.println("child.doSomething(),i=" + i--);
            super.doSomething();
            doSomething();
        }
    }
}

class Father {
    int i = 6;
    public synchronized void doSomething() {
        System.out.println("father.doSomething(),i=" + i--);
    }
}

child.doSomething(),i=6
father.doSomething(),i=5
child.doSomething(),i=4
father.doSomething(),i=3
child.doSomething(),i=2
father.doSomething(),i=1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值