Java并发编程之内置锁机制

在java多线程编程时,各个线程需要用到共享、可变的资源。由于多线程环境下,线程的执行顺序是无法预知的,所以需要对这些共享的、可变的资源加锁,使得线程可以顺序地访问共享资源,从而保证线程安全。这些共享、可变资源,我们称之为临界资源;锁根据不同的角度可以如下分类:

java中提供了两种方式来实现同步互斥访问synchronize和Lock。

synchronized原理详解



       synchronized内置锁是一种对象锁(锁的是对象而非引用),作用粒度是对象,可以用来实现对临界资源的同步互斥访问,是一种可重入锁。加锁的方式:

  • 同步实例方法,锁是当前实例对象
  • 同步类方法,锁是当前类对象
  • 同步代码块,锁是括号里面的对象

给对象方法加上synchronize修饰就可以实现实例方法的同步了,这种情况,锁是加在当前的对象实例上面;

public class ItemServcie {
    
    private int store;

    public synchronized int  increaseStore(){

        //....
      
           this.store++;
           System.out.println("to increase store:"+this.store);

       return this.store;
    }


    public synchronized int decreaseStore(){
        //....
        
            this.store--;
            System.out.println("to decrease store:"+this.store);
        
        return this.store;
    }

}

下面的代码采用锁代码块的方式来进行商品库存在多线程环境下的操作,保证库存的多线程安全:

public class ItemServcie {
    private Object storLock = new Object();
    private int store;

    public int increaseStore(){

        //....
       synchronized (storLock){
           this.store++;
           System.out.println("to increase store:"+this.store);
       }
       return this.store;
    }


    public int decreaseStore(){
        //....
        synchronized (storLock){
            this.store--;
            System.out.println("to decrease store:"+this.store);
        }
        return this.store;
    }

}

synchronized底层原理

synchronized关键字被编译成字节码后会被翻译成monitorenter 和monitorexit 两条指令分别放在同步块逻辑代码的起始位置与结束位置。我们知道synchronized加锁加在对象上,对象是如何记录锁
状态的呢?答案是锁状态是被记录在每个对象的对象头(Mark Word)中,下面我们一起认识一下对象的内存布局。

HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

  • 对象头:比如 hash码,对象所属的年代,对象锁,锁状态标志,偏向锁(线程)ID,偏向时间,数组长度(数组对象)等
  • 实例数据:即创建对象时,对象中成员变量,方法等
  • 对齐填充:对象的大小必须是8字节的

markword的长度和内容在32位虚拟机和64位虚拟机上不同:

     32位虚拟机上,不同锁状态markword各字段不同的内容如上图所示。

锁的膨胀升级过程

synchronize是jvm的内置锁,包含四个状态:无锁、偏向锁、轻量级锁、重量级锁。这是随着线程竞争的激烈程度而升级膨胀的,这个升级膨胀的过程是不可逆的。当没有线程进入同步代码块时,锁状态处于无锁状态;当同一个时刻只有一个线程处于同步代码块中时,这时转换成偏向锁,此时markword中会记录偏向的线程id;当多个线程同时刻竞争进入同步块时,锁进入轻量级锁;等待锁的线程自旋的获取锁,若果自旋次数超过一定数量,那么锁升级成重量级锁。

锁消除

锁消除是发生在编译器级别的一种锁优化方式。通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过这种方式消除没有必要的锁,可以节省毫无意义的请求锁时间。这时我们可以通过编译器将其优化,将锁消除,前提是java必须运行在server模式(server模式会比client模式作更多的优化),同时必须开启逃逸分析:

-server -XX:+DoEscapeAnalysis -XX:+EliminateLocks其中+DoEscapeAnalysis表示开启逃逸分析,+EliminateLocks表示锁消除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

子瑜1003

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值