synchronized中锁的升级过程

synchronized在操作过程中会访问操作系统,就是说java代码不能够让线程阻塞,过程依赖操作系统,所以是重量级锁

 

 

 

 

一个对象最少占16个字节,要做一个填充对齐,每个对象在内存中的大小都是8的倍数

 

对象头:java中的对象在内存中存储的时候有一个重要的组成部分,就是对象头,对象头中主要包括两部分数据:类型指针和标记字段,通过类型指针可以知道该对象是什么类型的,标记字段用来存储对象运行时的数据,其中就有锁对象的指针,它是我们理解Synchronized的关键,因为Synchronized使用到了各种锁。

标记字段中的锁对象指针指向了一个monitor对象,每个对象都有一个对应的monitor对象,monitor对象是同步工具,线程在执行加了Synchronized的代码段的时候要先去获取对象的monitor,执行完毕释放monitor。此过程是互斥的,一次只能有一个线程获取monitor,只有该线程释放monitor以后其它线程才能再获取它


 

public class MonitorDemo implements Runnable {
    int num = 0;
    Object o = new Object();
    @Override
    public void run() {
            synchronized (o) {
                    num++;
                    System.out.println(num);
                }
            }
}

线程一执行到“synchronized(o)”时获取到o对象的monitor进入同步代码块执行“num++; System.out.println(num);”,此时线程二执行“synchronized(o)”就无法获取o对象的monitor,只能等到线程一执行完同步代码块,将o的monitor释放才能获取到o的monitor,进入同步代码块执行。

当对某一段代码加上Synchronized关键字以后这段代码虽然拥有了线程安全性,但是效率也明显下降,如何在两者之间寻求平衡,在java1.6之后Synchronized进行了一些优化,引入了偏向锁、轻量级锁、重量级锁。

 

 

                                                               (大多数情况下,锁不仅不存在多线程竞争而且总是同一个线程获得这个锁,为了让获得锁的代价更低 CAS都不想做  偏向锁)   偏向锁撤锁会利用stop the world 由另一个线程来修改对象头会消耗cpu 尽量少使用

开机之后代码块运行这个对象,4s以后如果这个对象只有一个线程访问,会上一个偏向锁(实际上cas的wihle循环改成if)上面那一条线    


如果出现了多线程访问就会出现轻量级锁(用cas来完成去取锁),轻量级锁再发现很多线程再抢这把锁,在3-5ms中还抢不到(吞吐量高)就会升级为重量级锁或者偏向锁调用了wait等也会变成重量级锁(重量级锁是把线程阻塞起来)

(轻量锁的CAS自旋:当其他线程发现无法执行该代码的时候(也就是拿不到锁,一直cas的拿锁)它并不会挂起而是开始自旋,也就是在那里等待,不断的尝试执行(CAS自旋),该操作会消耗cpu.自旋因为线程不需要被挂起和唤醒,执行速度很快,但是此时cpu在不停的运转,所以吞吐量会较低)

CAS自旋多了会出现自适应自旋锁 次数控制 时间:一个线程的上下文切换时间

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值