synchronized

一、用法

synchronized可以用来锁方法和锁代码块。

锁方法又可以分成对象锁和类锁,synchronized加在普通方法上就是锁得是当前对象;加在static 的方法上锁的是当前类。

锁代码块也可以分成对象锁和类锁,在方法中使用synchronized(object)手动指定锁的对象;synchronized(object.class)锁的是类。类锁跟对象没关系。

public class SynchronizedCreat {
    Object object = new Object();//定义一个监视器
    /***
     * 用在方法上
     * 对象锁:锁SynchronizedCreat的new出来的对象
     */
    public synchronized void lock1(){ }
    /***
     * 用在方法上
     * 类锁:锁SynchronizedCreat这个类
     */
    public synchronized static  void lock2(){}
    /***
     * 锁代码块
     * 对象锁:锁的是Object的对象
     */
    public void lock3(){
        synchronized (object){
            //todo
        }
    }
    /***
     * 锁代码块
     * 类锁:锁的是SynchronizedCreat这个类
     */
    public void lock4(){
        synchronized (SynchronizedCreat.class){
            //todo
        }
    }
}

注:在普通方法上加锁,锁得是对象,哪个对象调用得这个加锁方法,锁的就是哪个对象。普通同步方法只能用在单例上,因为单例共用一个对象,多例中会有多个对象了,就是多把锁了。

二、特性

​ synchronized锁定一段代码或方法的时候,代表同一时刻最多只有一条线程执行这段代码,所以并发的原子性、可见性、有序性它都可以保证。

可重入性:synchronized是可以重入锁,同一个线程拿到锁后再遇到该锁,还可以获取该锁。它底层是通过一个计数器来实现的,获取该锁,计数器+1,在获取该锁,计数器再+1.释放锁,计数器-1,直到计数器为0,其他线程才可以竞争该锁。可重入性的好处是避免死锁。

不可被中断,不能响应超时:线程进入了锁里,其他线程只能在外面阻塞,没办法中断这个线程,如果这个线程发生死锁了,其他线程永远阻塞,可能导致程序崩溃。可以用ReentrantLock替换,它是可以被中断的。

当synchronized正常退出或抛出异常时会主动释放锁。

三、原理

​ synchronized在JVM里实现原理是基于进入和退出Monitor对象来实现方法同步和代码块同步的,他们的实现细节又不同。修饰代码块是通过monitorenter和monitorexit指令实现;修饰方法是通过标识ACC_SYNCHRONIZED来完成的。

​ 他们的本质都是对一个对象的监视器monitor进行获取和释放,而这个过程是排他的,同一时刻只允许一个线程获取受synchronized保护的监视器。
在这里插入图片描述

四、优化

​ synchronized是重量级锁,在jdk1.6之前可以认为是对应底层操作系统上的互斥量(mutex),使用synchrnoized会造成操作系统在用户态和内核态之间切换,线程上下文切换等,效率低。

​ 在jdk1.6之后对synchrnoized进行了升级,引入了偏向锁和轻量级锁.锁的状态分成了四种:无锁状态、偏向锁、轻量级锁、重量级锁。

​ 锁升级过程:一个对象刚创建就处于无锁状态,当又一个线程过来进入synchronized(o)代码里,此时这个对象o的锁就升级为偏向锁,这个对象o的对象头里的markword里记录着这个线程的id,当再有一个线程过来走到synchronized(o)时,开始等待拿锁,此时对象0锁状态升级为轻量级锁(自旋锁),这个线程在while do里一直等着(忙循环),轻量级锁如果自旋次数超过10次或者等待线程数量超过cpu核数的一半,就升级为重量级锁,重量级锁需要向操作系统申请。

锁可以升级但不能降级。偏向锁是一个自旋得过程,这个过程要占cpu资源得,重量级锁不占用cpu,但他会引起上下文切换,影响性能。

jdk1.6的优化还有锁粗化和锁消除

锁粗化:扩大加锁的范围,避免反复的加锁、释放锁,造成性能损耗,这个根据自己的应用场景选择使用。

锁消除:在编译期间去掉不可能存在竞争的锁,这样就不必再进行加锁、释放锁的操作了,提升性能。


版权声明:本文为csdn_binger原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。