synchronized的底层实现

上一篇文章博主简单介绍了synchronized的几种使用方法,下面来总结一下:

1.synchronized同步代码块:

  • synchronized(this):锁当前对象
  • synchronized(类.class):锁当前对象的class对象,即锁住类。相当于全局锁,锁住了一整块代码
  • synchronized(指定对象):锁指定对象

2.synchronized同步方法:

  • 普通方法+synchronized:锁的是调用该方法的当前对象
  • 静态方法+synchronized:全局锁,锁住了一整块代码

3.synchronized的底层实现:
synchronized的底层实现其实就是monitor机制,monitor就是一个对象的监听器,只有获取到monitor之后才能让同步代码块继续向下执行,否则只能等待。

(1) 同步代码块:

  • 进入同步代码块后,首先要执行monitorenter指令,退出时执行monitorexit指令。
  • 通常一个monitorenter指令包含多个monitorexit指令,这是为了保证线程所获得的锁不论是在正常路径,还是在异常路径都能被正常解锁。

(2) 同步方法:

  • 当使用synchronized来标记方法时,编译后字节码中方法的访问标记多了一个ACC_SYNCHRONIZED。

  • 这个标记表示:进入该方法时,JVM要进行monitorenter操作;
    退出该方法时,无论是否正常退出,都要进行monitorexit操作。

  • 当执行monitorenter指令时,若目标锁对象的monitor计数器值为0,表示当前锁没有被任何线程所拿到,此时将当前线程置为持有锁的线程,并让monitor计数器的值加一;

  • 若monitor计数器的值不为0,说明此时的锁已经被线程持有了:
    a. 判断持有锁的线程是不是当前线程,如果是当前线程,则再次将计数器的值加一,这就是锁的可重入性。
    b. 若不是,则要进行等待,直到锁被释放。

  • 当执行monitorexit指令时,monitor计数器的值会减一;若计数器的值减为0,则说明锁已经被释放了。

4.锁的特性与实现:

  • 锁的互斥性:即同一时刻只能有一个线程取得对象的monitor,从而保证同步。
class ReThread implements Runnable{

    @Override
    public void run() {
        synchronized (this){
            test11();
            test2();
        }
    }

    public void test11(){
        while(true){

        }
    }
    
    public synchronized void test2(){
        System.out.println(Thread.currentThread().getName()+"_test2 Running");
    }

}

public class ReTest {
    public static void main(String[] args) {
        ReThread reThread = new ReThread();
        Thread thread = new Thread(reThread);
        thread.start();
    }
}

此时,test11()拿到monitor对象后,一直没有释放锁,所以test2()处于等待状态,直到test11()释放锁。可见,同一时刻只能有一个线程可以拿到锁。

  • 锁的可重入性:即当一个线程拿到锁以后可以"为所欲为",可以继续拿到下一把锁。
class ReThread implements Runnable{

    @Override
    public void run() {
        synchronized (this){
            test1();
        }
    }

    public synchronized void test1(){
        System.out.println(Thread.currentThread().getName()+"_test1 Running");
        test2();
        System.out.println(Thread.currentThread().getName()+"_test1 End");
    }

    public synchronized void test2(){
        System.out.println(Thread.currentThread().getName()+"_test2 Running");
        System.out.println(Thread.currentThread().getName()+"_test2 End");
    }

}

public class ReTest {
    public static void main(String[] args) {
        ReThread reThread = new ReThread();
        Thread thread = new Thread(reThread);
        thread.start();
    }
}


结果如下:
在这里插入图片描述
可见,当test1()拿到锁以后,可以继续拿到下一个锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值