synchronized修饰于代码片段和静态方法,对于带代码片段或者非静态方法,synchronized是通过头对象中的MarkWord的信息来判断,MarkWord中有锁的类型,锁的地址等信息,对于静态方法,通过.Class文件来判断是否加锁.
在jdk1.6之前synchronized实现的方式就是重量锁,即通过操作系统的互斥量来实现加锁,在1.6之后出现了偏向锁,轻量锁,重量锁仍保留,作为等级最高的锁,锁的升级通过由JVM根据多线程下,等待线程的等待时间来判断是否升级,该参数可以进行手动修改
偏向锁,MarkWord字段存储的是线程ID,当有线程占用资源时,将线程id记录到MarkWord,其他线程访问资源时,发现MarkWord字段有值就会执行空循环等待(空循环不会导致阻塞,线程执行起来效率更高),当同一线程多次请求时,无需任何操作,效率得到提升,如果多线程情况下,锁的竞争激烈,那么该锁不适用
轻量锁,MarkWord字段储存的是锁的地址,锁存储在线程的栈帧中,如果其他线程等待时间过长,那么将会进入队列中,锁升级为重量级锁,同时采用非公平锁,其他线程过来之后也是等待一段时间在进队列,如果在等待的时间中,锁被释放,那么该线程将会优先执行,因为总体效率更高
自旋锁,轻量级锁失败后,虚拟机为了避免线程真实地在操作系统层面挂起,还会进行一项称为自旋锁的优化手段。这是基于在大多数情况下,线程持有锁的时间都不会太长,如果直接挂起操作系统层面的线程可能会得不偿失,毕竟操作系统实现线程之间的切换时需要从用户态转换到核心态,这个状态之间的转换需要相对比较长的时间,时间成本相对较高,因此自旋锁会假设在不久将来,当前的线程可以获得锁,因此虚拟机会让当前想要获取锁的线程做几个空循环(这也是称为自旋的原因),一般不会太久,可能是50个循环或100循环,在经过若干次循环后,如果得到锁,就顺利进入临界区。如果还不能获得锁,那就会将线程在操作系统层面挂起,这就是自旋锁的优化方式,这种方式确实也是可以提升效率的。最后没办法也就只能升级为重量级锁了。
重量级锁,通过操作系统层面的互斥量来实现
作用于变量上
volatile的特性为可见性和有序性,当一个线程对volatile修饰变量进行写操作时,jvm会立即将该变量强制刷入主内存中,当其他变量读取值时,会直接从主内存中读取
通过禁止指令重排保证有序性,具体实现是通过内存屏障来实现的,在每一条指令前后加上屏障指令,只有前面的指令执行完后才能执行后面的指令
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。