主要分为以下的几个锁(偏向锁 无锁 轻量级锁 重量级锁)
目录
偏向锁:大部分情况下,锁不仅仅不存在多线程竞争,而是总是由同一个线程多次获得,为了让线程获取锁的代价更低就引入了偏向锁。
无锁:一个对象如果没有被任何线程当做锁去使用,就是无锁状态。
轻量级锁: 一个对象如果被一个线程当做锁去使用,就是轻量级锁状态。
重量级锁:一个对象当做锁被一个线程持有,另外一个线程还继续去获取该锁,就是重量级锁。
偏向锁:大部分情况下,锁不仅仅不存在多线程竞争,而是总是由同一个线程多次获得,为了让线程获取锁的代价更低就引入了偏向锁。
没有开启偏向锁的情况下:
无锁:一个对象如果没有被任何线程当做锁去使用,就是无锁状态。
public class test2 {
public static void main(String[] args) {
A a=new A();
String str = ClassLayout.parseInstance(a).toPrintable();//获取锁的状态
System.out.println(str);
//此时是无锁的状态
}
}
class A{
}
在value的下面第一行中 01代表了无锁的状态
轻量级锁: 一个对象如果被一个线程当做锁去使用,就是轻量级锁状态。
public class test2 {
public static void main(String[] args) throws InterruptedException {
A a=new A();
String str = ClassLayout.parseInstance(a).toPrintable();//获取锁的状态
System.out.println(str);
//此时是无锁的状态
new Thread() {
public void run() {
//把a作为锁对象
synchronized(a) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
Thread.sleep(10);//保证线程获取锁对象
str = ClassLayout.parseInstance(a).toPrintable();//获取锁的状态
System.out.println(str);//此时该锁的为轻量级锁
}
}
class A{
}
此时value下的8位二进制数的后两位是 00 ,则代表是轻量级锁。
重量级锁:一个对象当做锁被一个线程持有,另外一个线程还继续去获取该锁,就是重量级锁。
public class test2 {
public static void main(String[] args) throws InterruptedException {
A a=new A();
String str = ClassLayout.parseInstance(a).toPrintable();//获取锁的状态
System.out.println(str);
//此时是无锁的状态
new Thread() {
public void run() {
//把a作为锁对象
synchronized(a) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
Thread.sleep(10);//保证线程获取锁对象
str = ClassLayout.parseInstance(a).toPrintable();//获取锁的状态
System.out.println(str);//此时该锁的为轻量级锁
//第二个线程
new Thread() {
public void run() {
//把a作为锁对象
synchronized(a) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
Thread.sleep(10);//保证线程获取锁对象
str = ClassLayout.parseInstance(a).toPrintable();//获取锁的状态
System.out.println(str);//此时该锁的为重量级锁。
//此时有两个线程,第一个线程已经获取了锁且没有释放锁,
//第二个线程要尝试获取该锁
}
}
class A{
}
此时value下的8位二进制数的后两位是 10,则代表是重量级锁。
开启偏向锁的情况下:
需要先进行修改
修改偏向锁的延迟时间的参数:-XX:BiasedLockingStartupDelay=0
无锁可偏向
public class test3 {
public static void main(String[] args) throws InterruptedException {
A a=new A();
String str = ClassLayout.parseInstance(a).toPrintable();//获取锁的状态
System.out.println(str);
}
}
此时value下的8位二进制数的后三位是 101,则代表是无锁可偏向锁。
轻量级锁可偏向
重级锁可偏向
public static void main(String[] args) throws InterruptedException {
A a = new A();
String str = ClassLayout.parseInstance(a).toPrintable();
System.out.println(str);//101 无锁可偏向
new Thread() {
public void run() {
synchronized(a) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*
* 显示的让当前线程不结束
* 如果结束了,下一个线程的id和刚才这个线程的id是一样的。
*/
try {
Thread.sleep(100000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
Thread.sleep(100);
str = ClassLayout.parseInstance(a).toPrintable();
System.out.println(str);//101 无锁可偏向
Thread.sleep(1000);//保证上一个线程已经把任务执行完毕了
new Thread() {
public void run() {
synchronized(a) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
Thread.sleep(100);
str = ClassLayout.parseInstance(a).toPrintable();
System.out.println(str);//
new Thread() {
public void run() {
synchronized(a) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
Thread.sleep(100);
str = ClassLayout.parseInstance(a).toPrintable();
System.out.println(str);//
}
}
此时value下的8位二进制数的后三位是 000,且后面不为0,则代表是可偏向轻量锁。
第二个8位的二进制有具体的数字则说明有偏向锁的ID,可以方便线程找到偏向锁。
此时value下的8位二进制数的后三位是 010,且后面不为0,则代表是可偏向重量锁。
第二个8位的二进制有具体的数字则说明有偏向锁的ID,可以方便线程找到偏向锁。
总结:
没有开启偏向锁的情况下:
一个对象没有被作为锁对象,处于无锁状态
一个对象被一个线程获取作为锁对象,处于轻量级锁状态
一个线程已经持有了该锁对象,其他线程来争用,处于重量级锁状态。
开启偏向锁的情况下:
一个对象没有被作为锁对象,处于无锁可偏向状态。(对象头中没有记录线程ID)
一个对象被一个线程作为锁对象,处于轻量级锁状态。(对象头中记录了线程ID)
一个对象被一个线程作为锁对象,释放锁对象后(但是该线程没有消亡时),其他线 程再获取该锁对象,则处于轻量级锁状态。
一个对象被一个线程作为锁对象,没有释放锁,其他线程也要获取该锁对象,就处 于重量级锁状态。