Synchronized

对象内存布局
JOL类库可以用来打印对象内存布局

Synchronized

用法:
修饰非静态方法,锁的是当前对象;
修饰静态方法,锁的是当前类的Class对象;
修饰代码块,锁的是括号里指定的对象(XX.class表示XX类的Class对象)

原理:
synchronized修饰代码块时,经过编译后,代码块对应的字节码指令前后会多出monitorenter和monitorexit指令,这两个指令是成对出现的,但是在发生异常的时候也要保证执行monitorexit指令来释放锁,所以monitorexit可能会多次出现。

synchronized修饰方法时,在class 文件的方法表中,对应的方法会有一个ACC_SYNCHRONIZED访问标志,它表示执行方法前需要线程先获取到锁。

锁升级:
1、锁状态保存在锁对象的对象头的Mark Word中,有四种:无锁、偏向锁、轻量锁、重量锁
2、不同状态下Mark Word存储的结构不同,偏向锁存的是偏向的线程id,轻量锁存的是指向线程栈帧中锁记录(Lock Record)的指针,重量锁存的是指向堆中monitor对象的指针。
3、锁只能升级不能降级,但是偏向锁可以重置为无锁。

偏向锁。不会主动释放,要么重置为无锁,要么升级为轻量锁。当锁第一次被线程获取时,会在对象头记录当前线程的id,同步代码执行完后,因为不释放锁,所以对象头中的线程id被保留,当这个线程再次获取锁时,判断线程id与锁对象头中的id一致,直接执行同步代码。若不一致,先根据id查看之前线程是否存活,若存活且仍需要持有锁,就将偏向锁升级为轻量锁,若不存活或者不再需要锁,则先将偏向锁重置为无锁,再存入新的线程id,重新变为偏向锁。

轻量锁。在栈帧中开辟一块内存Lock Record用来拷贝锁对象的Mark Word,并通过CAS操作将锁对象的Mark Word的内容变换为Lock Record的地址,释放锁时,再通过CAS操作将锁对象的Mark Word变回原来的样子。同步代码执行过程中,如果其他线程CAS操作失败则重试,重试超过一定次数或者又有第三个线程进行CAS操作时,轻量锁会升级为重量锁。

重量锁。重量锁会关联一个监视器,也就是monitor对象,这个monitor中保存了当前持有锁的线程、这个线程获取锁的次数、锁重入次数、等待锁的线程队列等信息。基于monitor可以实现代码的同步,当某个线程成功获取到monitor对象时,就代表它持有了锁,开始执行同步代码,在执行过程中,如果其他线程也尝试获取锁,根据互斥原则,会被放入monitor对象的等待队列中,并返回失败,陷入阻塞,直到锁被释放。

偏向锁:在只有一个线程执行同步块时提高性能(因为省略了加锁、解锁过程)
轻量锁:可以在线程交替执行同步块时提高性能(因为不需要切换上下文),缺点是自旋时会一直占用cpu,造成浪费
重量锁:互斥时会阻塞线程,进行上下文的切换,影响性能,但不会浪费cpu资源


重量锁和轻量锁的区别是:重量锁要依靠操作系统OS来管理锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值