偏向锁:大部分情况下,锁不仅仅不存在多线程竞争,而是总是由同一个线程多次获得,为了让线程获取锁的代价更低就引入了偏向锁。
没有开启偏向锁的情况下:
一个对象没有被作为锁对象,处于无锁状态
一个对象被一个线程获取作为锁对象,处于轻量级锁状态
一个线程已经持有了该锁对象,其他线程来争用,处于重量级锁状态
//没有开启偏向锁的情况
无锁状态
public class test {
public static void main(String[] args) {
A a=new A();
String str = ClassLayout.parseInstance(a).toPrintable();//获取锁的状态
System.out.println(str);
//此时是无锁的状态
}
}
轻量级锁状态
public class test {
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);//此时该锁的为轻量级锁
}
}
重量级锁状态
public class test1{
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{
}
开启偏向锁的情况下:
偏向锁的延迟时间的参数:-XX:BiasedLockingStartupDelay=0
一个对象没有被作为锁对象,处于无锁可偏向状态。(对象头中没有记录线程ID)
一个对象被一个线程作为锁对象,处于轻量级锁状态。(对象头中记录了线程ID)
一个对象被一个线程作为锁对象,释放锁对象后(但是该线程没有消亡时),其他线程再获取该锁对象,则处于轻量级锁状态。
一个对象被一个线程作为锁对象,没有释放锁,其他线程也要获取该锁对象,就处于重量级锁状态。
public class test {
public static void main(String[] args) throws InterruptedException {
A a=new A();
String str = ClassLayout.parseInstance(a).toPrintable();//获取锁的状态
System.out.println(str);
}
}
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);//
}
}