1、对象的状态有几种:
无锁、偏向锁、轻量级锁、重量级锁、GC标记,共5个状态
2、锁的膨胀过程
- 无锁:程序多线程执行过程中没有去执行synchronized修饰区域或者方法。
- 偏向锁:发生在程序单线程执行过程中,由始至终只有一个线程去执行过synchronized修饰区域或者方法,由于是由始至终只有一个线程去执行所以没有发生竞争、等待、抢锁的情况,它不会调用操作系统的函数去实现同步。
- 轻量级锁:发生在程序多线程执行过程中有去执行synchronized修饰区域或者方法,且没有发生竞争、等待、抢锁的情况或者发生了竞争、等待、抢锁但是竞争、等待和抢锁的时间没有超过一个JVM设定的自旋时间或者次数的时候,它是在虚拟机内部去实现的同步,不会调用操作系统的函数去实现同步。
- 重量级锁:发生在程序多线程执行过程中有去执行synchronized修饰区域或者方法,且发生了竞争、等待、抢锁且竞争、等待和抢锁的时间已经超过一个JVM设定的自旋时间或者次数的时候,它会调用操作系统的函数去实现同步(调用操作系统实现同步,需要的步骤很多,导致性能相对于其它锁实现同步的方式就很低)。
3、锁的标识码
- 无 锁 001
- 偏 向 锁 101
- 轻量级锁 000
- 重量级锁 010
示例如下:
通过 -XX:BiasedLockingStartupDelay=0 可以设置延迟开启偏向锁的时间
4、几种锁的效率对比
- 无 锁: 耗时61毫秒
- 偏 向 锁: 耗时2051毫秒
- 轻量级锁: 耗时18302毫秒
- 重量级锁: 耗时43470毫秒
下面是无锁、偏向锁、轻量级锁 耗时测试代码
package day07.part1;
/**
* synchronized关键字的底层原理
*
* 偏向锁和轻量级锁对比
* -XX:BiasedLockingStartupDelay=0 立即开启偏向锁
* -XX:BiasedLockingStartupDelay=30000 30秒后再开启偏向锁 那30秒以前开启的是轻量级锁
*
* 无锁:不设置偏向锁,不加synchronized关键字 用时是:61毫秒
* 偏向锁:设置偏向锁,加synchronized关键字 即使没有线程
* 安全问题需要同步,那么加上了synchronized也就
* 有了同步的嫌疑,所以jvm还是给它加了一把偏向锁 用时是:2051毫秒
*
* 轻量级锁:不设置偏向锁,加synchronized关键字 用时是:18302毫秒
* 轻量级锁:设置偏向锁30秒后开启,加synchronized关键字 用时是:17702毫秒
*
*
* @author xzq
*/
public class SynchronizedBottomTest07 {
public static void main(String[] args) throws InterruptedException {
Test test=new Test();
long beforeTime = System.currentTimeMillis();
//执行10亿次
for(int i=0;i<1000000000;i++){
test.testIncreament();
}
long endTime = System.currentTimeMillis();
System.out.println("用时是:"+(endTime-beforeTime)+"毫秒");
}
static class Test{
private int l=0;
public synchronized void testIncreament(){
l++;
}
}
}
重量级锁耗时示例
例子中2个线程竞争 直接上来就加了重量级锁。
package day07.part1;
import java.util.concurrent.CountDownLatch;
/**
* synchronized关键字的底层原理
*
* 轻量级锁和重量级锁对比
*
* 用时是:45035毫秒
* -XX:BiasedLockingStartupDelay=0
* 配置-XX:BiasedLockingStartupDelay=0 后 耗时依然有 用时是:44878毫秒
* 说明2个线程竞争 直接上来就加了重量级锁 而不会上偏向锁
* @author xzq
*/
public class SynchronizedBottomTest08 {
private static CountDownLatch cdLatch=new CountDownLatch(1000000000);
public static void main(String[] args) throws InterruptedException {
final Test test=new Test();
long beforeTime = System.currentTimeMillis();
//创建两个线程去执行,这样就产生了竞争就是重量级锁
for(int i=0;i<2;i++){
new Thread(){
@Override
public void run() {
//执行10亿次
while(cdLatch.getCount()>0){
test.testIncreament();
}
}
}.start();
}
cdLatch.await();
long endTime = System.currentTimeMillis();
System.out.println("用时是:"+(endTime-beforeTime)+"毫秒");
}
static class Test{
private int l=0;
public synchronized void testIncreament(){
l++;
cdLatch.countDown();
}
}
}
5、锁的膨胀过程
代码示例
package day07.part1;
import org.openjdk.jol.info.ClassLayout;
/**
* synchronized关键字的底层原理
*
* 演示整个锁的膨胀过程和成为重量级锁后
* 所有线程退出同步代码区域后,MarkWord是什么锁状态 这里测试结果为无锁状态
* -XX:BiasedLockingStartupDelay=0
* 无锁 001
* 偏向锁 101
* 轻量级锁 000
* 重量级锁 010
*
* @author xzq
*/
public class SynchronizedBottomTest09 {
public static void main(String[] args) throws InterruptedException {
Thread mainThread = Thread.currentThread();
mainThread.setName("主线程:");
final Test testLock=new Test();
System.out.println("--------------------------所有线程加锁前------------------------------------");
System.out.println(ClassLayout.parseInstance(testLock).toPrintable());//无锁
Thread t=new Thread("子线程:"){
@Override
public void run() {
String threadName = Thread.currentThread().getName();
synchronized (testLock) {
System.out.println(threadName+"---------------------------------加锁后----------------------------");
System.out.println(ClassLayout.parseInstance(testLock).toPrintable());//轻量级锁
//休眠3秒
try {Thread.sleep(3_000);} catch (InterruptedException e) {}
}
System.out.println(threadName+"---------------------------------释放了锁!----------------------------");
}
};
t.start();
Thread.sleep(1000);
//让主线程和子线程产生竞争、抢锁
synchronized (testLock) {
System.out.println("------------------------------主线程和子线程发生竞争抢锁-------------------------------");
System.out.println(ClassLayout.parseInstance(testLock).toPrintable());//重量级锁
}
Thread.sleep(5_000);
System.out.println("---------------------------------主线程和子线程都释放了锁!----------------------------");
System.out.println(ClassLayout.parseInstance(testLock).toPrintable());//重量级锁
}
static class Test{
}
}
测试结果如下:
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=55003:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/tools.jar:/Users/xuzhiqiang/ideaProjects/SpringBoot/synchronize/target/classes:/Users/xuzhiqiang/.m2/repository/org/openjdk/jol/jol-core/0.9/jol-core-0.9.jar day07.part1.SynchronizedBottomTest09
--------------------------所有线程加锁前------------------------------------
# WARNING: Unable to attach Serviceability Agent. You can try again with escalated privileges. Two options: a) use -Djol.tryWithSudo=true to try with sudo; b) echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
day07.part1.SynchronizedBottomTest09$Test object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) a0 c1 00 f8 (10100000 11000001 00000000 11111000) (-134168160)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
子线程:---------------------------------加锁后----------------------------
day07.part1.SynchronizedBottomTest09$Test object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) a8 19 ea 03 (10101000 00011001 11101010 00000011) (65673640)
4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
8 4 (object header) a0 c1 00 f8 (10100000 11000001 00000000 11111000) (-134168160)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
------------------------------主线程和子线程发生竞争抢锁-------------------------------
子线程:---------------------------------释放了锁!----------------------------
day07.part1.SynchronizedBottomTest09$Test object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 4a 7f 80 ed (01001010 01111111 10000000 11101101) (-310345910)
4 4 (object header) 9e 7f 00 00 (10011110 01111111 00000000 00000000) (32670)
8 4 (object header) a0 c1 00 f8 (10100000 11000001 00000000 11111000) (-134168160)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
---------------------------------主线程和子线程都释放了锁!----------------------------
day07.part1.SynchronizedBottomTest09$Test object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) a0 c1 00 f8 (10100000 11000001 00000000 11111000) (-134168160)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
Process finished with exit code 0