synchronized——可重入性

来源:互联网 发布:淘宝怎么好评改差评 编辑:程序博客网 时间:2024/05/21 06:40

一、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

0 0