谈谈synchronized关键字

本文解释了synchronized的作用、在并发编程中的重要性,以及从JDK1.6起的性能优化。重点介绍了synchronized在实例方法、静态方法和代码块中的使用,并讨论了相关的问题和底层实现机制,包括monitorenter/monitorexit指令的应用。
摘要由CSDN通过智能技术生成

synchronized是什么?

synchronized为同步之意,可保证在同一时刻,被它修饰的方法或代码块只能有一个线程执行,它的使用解决了并发多线程中的三大问题:原子性、可见性、顺序性

有的书籍中可能会看到说synchronized是一种重量级锁,性能差,不建议在代码中使用,其实这是早期的synchronized特点,自JDK1.6之后,synchronized 引入了大量的优化如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销,这些优化让 synchronized 锁的效率提升了很多。因此, synchronized 在JDK 源码、很多开源框架都大量使用了 synchronized 。

synchronized的使用

synchronized在Java中主要的3种使用方式:

  1. 修饰实例方法: 为当前对象实例加锁,进入同步方法需要先获取对象锁;

  2. 修饰静态方法: 为当前类加锁,锁定的是Class对象,进入同步方法需要先获取类锁;

  3. 修饰代码块:  为指定对象加锁,进入同步方法需要先获取指定对象的锁。

样例:

//修饰实例方法,为当前实例加锁
synchronized void method() {
    //业务代码
}
//修饰静态方法,锁为当前Class对象
synchronized static void method() {
    //业务代码
}
//修饰代码块,锁为括号里面的对象
synchronized(this) {
    //业务代码
}

这里有几个问题:

1:synchronized修饰代码块可以给类加锁吗?

可以,前面说了修饰代码块时,是给代码中的对象加锁,这里面的对象既可以是实例也可以是类。

2:静态 synchronized 方法和非静态 synchronized 方法之间的调用互斥吗?

不互斥,如果线程A调用一个实例对象的非静态synchronized方法,线程B同时去调用这个实例对象所属类的静态synchronized方法并不会发生互斥,因为线程A此时拿到的是实例对象锁,而线程B拿到的是当前类的锁。

3:构造方法可以用 synchronized 修饰吗?

不可以,构造方法本身就是线程安全的,在Java开发规范里也明确告诉我们。

构造方法不能是抽象的(abstract)、静态的(static)、最终的(final)、同步的(synchronized)。

synchronized的底层原理

在synchronized的底层(JVM层面),针对方法与代码块的实现逻辑是不同的,因此我们在分析底层原理时也要分别来看。

1、当synchronized修饰方法时

public class Test {
    public synchronized void method() {
        System.out.println("synchronized 方法");
    }
}

我们通过对编译后的class文件进行反编译后,分析其底层实现。

知识点扩展:我们通过javap命令进行反编译,javap是Java class文件分解器,可以反编译,也可以查看java编译器生成的字节码等。javap参数如下:

使用方式,既可以在电脑的命令行提示符中使用,也可以通过idea的terminal终端使用,参考命令:javap -c -v Test.class 

反汇编结果

由上图可看出同步方法通过加 ACC_SYNCHRONIZED 标识实现线程的执行权的控制,如果修饰的是实例方法,JVM会获取对象锁,如果修饰的是静态方法,JVM会获取当前类锁。 

2、当synchronized修饰代码块时

public class Test {
    public void method() {
        synchronized (this) {
            System.out.println("synchronized");
        }
    }
}

 反汇编结果

与同步方法不同,同步代码块中使用了monitorenter 和 monitorexit 指令,其中 monitorenter 指令指向同步代码块的开始位置,monitorexit 指令则指明同步代码块的结束位置,并且monitorexit标识有2个,以保证在正常执行和异常情况下均可释放锁。

在命令执行到monitorenter时,线程会去尝试获取对象的锁。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值