" />

最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JAVA偏向鎖的原理與實戰(zhàn)

 更新時間:2022年03月14日 14:42:03   作者:CodePanda@GPF  
這篇文章主要為大家詳細介紹了JAVA偏向鎖的原理與實戰(zhàn),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助

1. 偏向鎖的核心原理

如果不存在線程競爭的一個線程獲得了鎖,那么鎖就進入偏向狀態(tài),此時Mark Word的結(jié)構(gòu)變?yōu)槠蜴i結(jié)構(gòu),鎖對象的鎖標志位(lock)被改為01,偏向標志位(biased_lock)被改為1,然后線程的ID記錄在鎖對象的Mark Word中(使用CAS操作完成)。以后該線程獲取鎖時判斷一下線程ID和標志位,就可以直接進入同步塊,連CAS操作都不需要,這樣就省去了大量有關(guān)鎖申請的操作,從而也就提升了程序的性能。

關(guān)鍵點:無競爭

缺點:如果鎖對象時常被多個線程競爭,偏向鎖就是多余的,并且其撤銷的過程會帶來一些性能開銷

2. 偏向鎖代碼演示

偏向鎖是默認是延遲的,不會在程序啟動時立即生效,如果想避免延遲,可以加 VM 參數(shù)

-XX:BiasedLockingStartupDelay=0 來禁用延遲

package innerlock;
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;
public class InnerLockTest {
	int a=1;
	double b=1.1;
	public static void main(String[] args) {
		System.out.println(VM.current().details());
		Person person=new Person();
		ClassLayout layout=ClassLayout.parseInstance(person);
		new Thread(()->{
			System.out.println("獲取偏向鎖前:");
			System.out.println(layout.toPrintable());
			synchronized (person) {
				System.out.println("獲取偏向鎖中:");
				System.out.println(layout.toPrintable());
			}
			System.out.println("獲取偏向鎖結(jié)束后:");
			System.out.println(layout.toPrintable());
		}
		,"thread1").start();
	}
}
class Person{
}

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

禁用偏向鎖:添加 VM 參數(shù) -XX:-UseBiasedLocking

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

3. 偏向鎖的膨脹與撤銷

假如有多個線程來競爭偏向鎖,此對象鎖已經(jīng)有所偏向,其他的線程發(fā)現(xiàn)偏向鎖并不是偏向自己,就說明存在了競爭,嘗試撤銷偏向鎖(很可能引入安全點),然后膨脹到輕量級鎖

1. 偏向鎖的撤銷

1.在一個安全點停止擁有鎖的線程

2.遍歷線程的棧幀,檢查是否存在鎖記錄。如果存在鎖記錄,就需要清空鎖記錄,使其變成無鎖狀態(tài),并修復(fù)鎖記錄指向的Mark Word,清除其線程ID

3.將當前鎖升級成輕量級鎖

4.喚醒當前線程

撤銷偏向鎖的條件(滿足其一即可):

1.多個線程競爭偏向鎖

2.調(diào)用偏向鎖對象的hashcode()方法或者System.identityHashCode()方法計算對象的HashCode之后,將哈希碼放置到Mark Word中,內(nèi)置鎖變成無鎖狀態(tài),偏向鎖將被撤銷

2. 批量重偏向與撤銷

批量重偏向解決的問題:

一個線程創(chuàng)建了大量對象并執(zhí)行了初始的同步操作,之后在另一個線程中將這些對象作為鎖進行之后的操作。這種case下,會導(dǎo)致大量的偏向鎖撤銷操作。

package innerlock;
import java.util.ArrayList;
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;
public class InnerLockTest {
	int a=1;
	double b=1.1;
	public static void main(String[] args) throws InterruptedException {
		System.out.println(VM.current().details());
		ArrayList<Person> list=new ArrayList<Person>();
		new Thread(()->{
			for(int i=0;i<100;i++)
			{
				Person person=new Person();
				synchronized (person) {
					list.add(person);
				}
			}
			try {
				Thread.sleep(10000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		,"thread1").start();
		Thread.sleep(3000);
		new Thread(()->{
			for(int i=0;i<30;i++)
			{
				Person person=list.get(i);
				synchronized (person) {
					if(i==17||i==18||i==19||i==21)
					{
						System.out.println("第"+(i+1)+"次偏向結(jié)果:");
						System.out.println(ClassLayout.parseInstance(person).toPrintable());
					}
				}
			}
		}
		,"thread2").start();
	}
}
class Person{
}

在這里插入圖片描述

在這里插入圖片描述

結(jié)果分析:

先用線程1創(chuàng)建了100個對象鎖,這些對象鎖都偏向于線程1,后面創(chuàng)建線程2去爭奪這些鎖,前19次線程2都是搶占失敗獲得輕量級鎖(失敗過程中閾值增加),第20次搶占時達到閾值20,這時JVM會認為自己是不是不應(yīng)該偏向線程1,于是之后開始偏向線程2,線程2之后獲得的都是偏向鎖

  • 第1-19個對象由于線程2在搶占過程中變?yōu)檩p量級鎖,鎖釋放后變?yōu)闊o鎖狀態(tài)
  • 第20-30個對象觸發(fā)批量重定向,鎖釋放后依舊偏向線程2
  • 第31-100個對象依然和開始一樣偏向線程1,鎖釋放后依舊偏向線程1

批量撤銷解決的問題:

存在明顯多線程競爭的場景下使用偏向鎖是不合適的,例如生產(chǎn)者/消費者隊列

package innerlock;
import java.util.ArrayList;
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;
public class InnerLockTest {
	int a=1;
	double b=1.1;
	public static void main(String[] args) throws InterruptedException {
		System.out.println(VM.current().details());
		ArrayList<Person> list=new ArrayList<Person>();
		new Thread(()->{
			for(int i=0;i<100;i++)
			{
				Person person=new Person();
				synchronized (person) {
					list.add(person);
				}
			}
			try {
			//為了防止JVM線程復(fù)用,在創(chuàng)建完對象后,保持線程t1狀態(tài)為存活
				Thread.sleep(10000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		,"thread1").start();
		Thread.sleep(3000);
		new Thread(()->{
			for(int i=0;i<40;i++)
			{
				Person person=list.get(i);
				synchronized (person) {
					if(i==18||i==19||i==39||i==41)
					{
						System.out.println("t2  第"+(i+1)+"次偏向結(jié)果:");
						System.out.println(ClassLayout.parseInstance(person).toPrintable());
					}
				}
			}
			try {
				Thread.sleep(10000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		,"thread2").start();
		Thread.sleep(3000);
		new Thread(()->{
			for(int i=20;i<40;i++)
			{
				Person person=list.get(i);
				synchronized (person) {
					if(i==20||i==39)
					{
						System.out.println("t3   第"+(i+1)+"次偏向結(jié)果:");
						System.out.println(ClassLayout.parseInstance(person).toPrintable());
					}
				}
			}
		}
		,"thread3").start();
		Thread.sleep(1000);
		System.out.println("新創(chuàng)建對象:"+ClassLayout.parseInstance(new Person()).toPrintable());
	}
}
class Person{
}

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

做法:

以class為單位,為每個class維護一個偏向鎖撤銷計數(shù)器,每一次該class的對象發(fā)生偏向撤銷操作時,該計數(shù)器+1,當這個值達到重偏向閾值默認20時,JVM就認為該class的偏向鎖有問題,因此會進行批量重偏向。每個class對象會有一個對應(yīng)的epoch字段,每個處于偏向鎖狀態(tài)對象的mark word中也有該字段,其初始值為創(chuàng)建該對象時,class中的epoch的值。每次發(fā)生批量重偏向時,就將該值+1,同時遍歷JVM中所有線程的棧,找到該class所有正處于加鎖狀態(tài)的偏向鎖,將其epoch字段改為新值。下次獲得鎖時,發(fā)現(xiàn)當前對象的epoch值和class的epoch不相等,那就算當前已經(jīng)偏向了其他線程,也不會執(zhí)行撤銷操作,而是直接通過CAS操作將其mark word的Thread Id 改成當前線程Id

當達到重偏向閾值后,假設(shè)該class計數(shù)器繼續(xù)增長,當其達到批量撤銷的閾值后(默認40),JVM就認為該class的使用場景存在多線程競爭,會標記該class為不可偏向,之后,對于該class的鎖,直接走輕量級鎖的邏輯

小結(jié):

在這里插入圖片描述

3. 偏向鎖的膨脹

如果偏向鎖被占據(jù),一旦有第二個線程爭搶這個對象,因為偏向鎖不會主動釋放,所以第二個線程可以看到內(nèi)置鎖偏向狀態(tài),這時表明在這個對象鎖上已經(jīng)存在競爭了。JVM檢查原來持有該對象鎖的占有線程是否依然存活,如果掛了,就可以將對象變?yōu)闊o鎖狀態(tài),然后進行重新偏向,偏向搶鎖線程。如果JVM檢查到原來的線程依然存活,就進一步檢查占有線程的調(diào)用堆棧是否通過鎖記錄持有偏向鎖。如果存在鎖記錄,就表明原來的線程還在使用偏向鎖,發(fā)生鎖競爭,撤銷原來的偏向鎖,將偏向鎖膨脹(INFLATING)為輕量級鎖

總結(jié)

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • 使用Java生成JWT(JSON Web Token)的方法示例

    使用Java生成JWT(JSON Web Token)的方法示例

    在現(xiàn)代應(yīng)用程序中,身份驗證和授權(quán)是至關(guān)重要的,JWT是一種簡單而強大的身份驗證和授權(quán)機制,可以在Web應(yīng)用程序中安全地傳輸用戶信息,本文主要介紹了使用Java生成JWT的方法示例,感興趣的可以了解一下
    2024-03-03
  • IntelliJ IDEA導(dǎo)入Gradle項目的方法

    IntelliJ IDEA導(dǎo)入Gradle項目的方法

    這篇文章主要介紹了IntelliJ IDEA導(dǎo)入Gradle項目的方法,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • 淺談Java序列化和反序列化為何要實現(xiàn)Serializable接口

    淺談Java序列化和反序列化為何要實現(xiàn)Serializable接口

    這篇文章主要介紹了淺談Java序列化和反序列化為何要實現(xiàn)Serializable接口,序列化最重要的作用是在傳遞和保存對象時.保證對象的完整性和可傳遞性,對象轉(zhuǎn)換為有序字節(jié)流,以便在網(wǎng)絡(luò)上傳輸或者保存在本地文件中,需要的朋友可以參考下
    2023-12-12
  • java的Arrays工具類實戰(zhàn)

    java的Arrays工具類實戰(zhàn)

    java.util.Arrays類能方便地操作數(shù)組,它提供的所有方法都是靜態(tài)的。Arrays作為一個工具類,能很好的操作數(shù)組。下面介紹主要使用的幾個函數(shù)
    2016-12-12
  • 深入理解Netty?FastThreadLocal優(yōu)缺點及實現(xiàn)邏輯

    深入理解Netty?FastThreadLocal優(yōu)缺點及實現(xiàn)邏輯

    本文以線上詭異問題為切入點,通過對比JDK ThreadLocal和Netty FastThreadLocal實現(xiàn)邏輯以及優(yōu)缺點,并深入解讀源碼,由淺入深理解Netty FastThreadLocal
    2023-10-10
  • Java中的this和super實例淺析

    Java中的this和super實例淺析

    要說this和super就不得不說Java的封裝和繼承了。這篇文章主要介紹了Java中的this和super實例淺析,需要的朋友可以參考下
    2017-03-03
  • 關(guān)于二分法查找Java的實現(xiàn)及解析

    關(guān)于二分法查找Java的實現(xiàn)及解析

    這篇文章主要介紹了關(guān)于二分法查找Java的實現(xiàn)及解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • Spring零基礎(chǔ)入門WebFlux響應(yīng)式編程

    Spring零基礎(chǔ)入門WebFlux響應(yīng)式編程

    Spring 提供了兩個并行堆棧,一種是基于帶有 Spring MVC 和 Spring Data 結(jié)構(gòu)的 Servlet API,另一個是完全反應(yīng)式堆棧,它利用了 Spring WebFlux 和 Spring Data 的反應(yīng)式存儲庫,這篇文章主要介紹了Spring-webflux 響應(yīng)式編程,需要的朋友可以參考下
    2022-10-10
  • 如何用好Java枚舉讓你的工作效率飛起來

    如何用好Java枚舉讓你的工作效率飛起來

    在JDK1.5之前沒有枚舉類型,那時候一般用接口常量來替代,而使用Java枚舉類型enum可以更貼近地表示這種常量,下面這篇文章主要給大家介紹了關(guān)于如何用好Java枚舉讓你的工作效率飛起來的相關(guān)資料,需要的朋友可以參考下
    2021-09-09
  • Java 編程如何使用 Class.forName() 加載類

    Java 編程如何使用 Class.forName() 加載類

    在一些應(yīng)用中,無法事先知道使用者將加載什么類,而必須讓使用者指定類名稱以加載類,可以使用 Class的靜態(tài)forName()方法實現(xiàn)動態(tài)加載類,這篇文章主要介紹了Java編程如何使用Class.forName()加載類,需要的朋友可以參考下
    2022-06-06

最新評論

龙川县| 扶沟县| 紫云| 娄底市| 阜康市| 五大连池市| 名山县| 五莲县| 稷山县| 沽源县| 牟定县| 曲靖市| 山阴县| 牟定县| 通山县| 澄城县| 冷水江市| 襄樊市| 水富县| 巨野县| 卫辉市| 西乌| 裕民县| 沙河市| 三门峡市| 泸西县| 石河子市| 惠安县| 玉林市| 平舆县| 沐川县| 新河县| 林口县| 邵阳市| 利津县| 喀什市| 辽阳市| 堆龙德庆县| 南澳县| 兴化市| 巴青县|