synchronized关键字详解(二)

synchronized关键字的性质

1.可重入:同一线程的外层函数获得锁之后,内层函数可直接再次获得该锁,好处:避免死锁,提升封装性

证明可重入粒度:1、同一个方法是可重入的

        2、可重入不要求是同一个方法

        3、可重入不要求是同一个类

可重入原理:加锁次数计数器

      • JVM负责跟踪对象被加锁的次数;
      • 线程第一次给对象加锁的时候计数变为1,每当这个相同的线程在这个对象上加锁时,计数递增;
      • 每当任务离开时,计数会减1,计数为0时,锁被完全释放。

2.不可中断:如果一个线程拿到一把锁,另一个线程要想获得这把锁,只能等待或者阻塞,直到别的线程释放这个锁,如果另一个线程一直不释放,那就只能一直等待下去。(相比之下,Lock类拥有中断的能力:1.lock如果等的时间太长,有权利中断当前获得锁的这个线程;2.lock等待时间太长不想等,可以自动退出)

同一个方法是可重入的:

递归调用method方法打印出a=1;就说明进入该方法两次

/**
 * 
 * 验证synchronized的可重入性质1:
 * 同一个方法是可重入的
 * @author Administrator
 *
 */
public class SynchronizeTest04 implements Runnable{
    static SynchronizeTest04 instance1 = new SynchronizeTest04();
    int a = 0;
    @Override
    public void run() {
        //调用加synchronized关键字的普通方法
        method();
    }
    public synchronized void method() {
        System.out.println("a="+a);
        if(a==0) {
            a++;
            method();
        }    
    }
    public static void main(String[] args) {
        Thread t1 = new Thread(instance1,"线程一");
        t1.start();
        while(t1.isAlive()) {
            
        }
        System.out.println("执行结束");
    }
}

 

 

 

可重入不要求是同一个方法:

run方法中调用被synchronized修饰的method1方法,在method1中调用被synchronized修饰的method2方法

/**
 * 
 * 验证synchronized的可重入性质2:
 * 可重入不要求是同一个方法
 * @author Administrator
 *
 */
public class SynchronizeTest04 implements Runnable{
    static SynchronizeTest04 instance1 = new SynchronizeTest04();
    int a = 0;
    @Override
    public void run() {
        //调用加synchronized关键字的普通方法
        method1();
    }
    public synchronized void method1() {
        System.out.println("我是方法一");
        method2();
    }
    public synchronized void method2() {
        System.out.println("我是方法二");
    }
    public static void main(String[] args) {
        Thread t1 = new Thread(instance1,"线程一");
        t1.start();
        while(t1.isAlive()) {
            
        }
        System.out.println("执行结束");
    }
}
可重入不要求是同一个方法

 

 

可重入不要求是同一个类:

由于main方法就是一个线程,所以这里用main方法演示,父类中创建被synchronized修饰的doSomething方法,子类中重写doSomething方法,并调用父类方法

/**
 * 
 * 验证synchronized的可重入性质3:
 * 可重入不要求是同一个类
 * @author Administrator
 *
 */
public class SynchronizeTest05 {
    public synchronized void doSomething() {
        System.out.println("我是父类");
    }
    public static void main(String[] args) {
        Test t = new Test();
        t.doSomething();
    }
}
class Test extends SynchronizeTest05{
    //重写父类的方法,并调用父类方法
    public synchronized void doSomething() {
        System.out.println("我是子类");
        super.doSomething();
    }
}
可重入不要求是同一个类

 

synchronized关键字的缺点:

1、效率低:锁的释放少,试图获得锁时不能设置超时,不能中断一个正在获得锁的线程;

2、不够灵活:加锁和释放的时机单一,每个锁仅有单一的条件

3、无法知道是否成功获取到锁

在使用synchronized关键字时注意:锁对象不能为空、锁的作用域不宜过大、避免死锁。

 

posted @ 2019-05-03 17:42  LikFre  阅读(197)  评论(0编辑  收藏  举报