0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

Java并發(fā)編程中線程同步的常用手段synchronized用法

FPGA之家 ? 來源:sowhat1412 ? 作者:sowhat1412 ? 2021-04-04 11:30 ? 次閱讀

synchronized關鍵字是Java并發(fā)編程中線程同步的常用手段之一,其作用有三個:

互斥性:確保線程互斥的訪問同步代,鎖自動釋放,多個線程操作同個代碼塊或函數(shù)必須排隊獲得鎖,

可見性:保證共享變量的修改能夠及時可見,獲得鎖的線程操作完畢后會將所數(shù)據(jù)刷新到共享內(nèi)存區(qū)[1]

有序性:不解決重排序,但保證有序性

synchronized用法有三個:

修飾實例方法

修飾靜態(tài)方法

修飾代碼塊

1. 修飾實例方法

synchronized關鍵詞作用在方法的前面,用來鎖定方法,其實默認鎖定的是this對象。

publicclassThread1implementsRunnable{ //共享資源(臨界資源)staticinti=0; //如果沒有synchronized關鍵字,輸出小于20000publicsynchronizedvoidincrease(){ i++; } publicvoidrun(){ for(intj=0;j<10000;j++){ ????????????increase(); ????????} ????} ????public?static?void?main(String[]?args)?throws?InterruptedException?{ ????????Thread1?t=new?Thread1(); ????????Thread?t1=new?Thread(t); ????????Thread?t2=new?Thread(t); ????????t1.start(); ????????t2.start(); ????????t1.join();//主線程等待t1執(zhí)行完畢????????t2.join();//主線程等待t2執(zhí)行完畢????????System.out.println(i); ????} }

2a18f1b6-8ecb-11eb-8b86-12bb97331649.png


2. 修飾靜態(tài)方法

synchronized還是修飾在方法上,不過修飾的是靜態(tài)方法,等價于鎖定的是Class對象,

publicclassThread1{ //共享資源(臨界資源)staticinti=0; //如果沒有synchronized關鍵字,輸出小于20000publicstaticsynchronizedvoidincrease(){ i++; } publicstaticvoidmain(String[]args)throwsInterruptedException{ Threadt1=newThread(newRunnable(){ publicvoidrun(){ for(intj=0;j

2a18f1b6-8ecb-11eb-8b86-12bb97331649.png


3. 修飾代碼塊

用法是在函數(shù)體內(nèi)部對于要修改的參數(shù)區(qū)間用synchronized來修飾,相比與鎖定函數(shù)這個范圍更小,可以指定鎖定什么對象。

publicclassThread1implementsRunnable{ //共享資源(臨界資源)staticinti=0; @Overridepublicvoidrun(){ for(intj=0;j

2a18f1b6-8ecb-11eb-8b86-12bb97331649.png

總結(jié):

synchronized修飾的實例方法,多線程并發(fā)訪問時,只能有一個線程進入,獲得對象內(nèi)置鎖,其他線程阻塞等待,但在此期間線程仍然可以訪問其他方法。

synchronized修飾的靜態(tài)方法,多線程并發(fā)訪問時,只能有一個線程進入,獲得類鎖,其他線程阻塞等待,但在此期間線程仍然可以訪問其他方法。

synchronized修飾的代碼塊,多線程并發(fā)訪問時,只能有一個線程進入,根據(jù)括號中的對象或者是類,獲得相應的對象內(nèi)置鎖或者是類鎖

每個類都有一個類鎖,類的每個對象也有一個內(nèi)置鎖,它們是互不干擾的,也就是說一個線程可以同時獲得類鎖和該類實例化對象的內(nèi)置鎖,當線程訪問非synchronzied修飾的方法時,并不需要獲得鎖,因此不會產(chǎn)生阻塞。

管程

管程[2](英語:Monitors,也稱為監(jiān)視器) 在操作系統(tǒng)中是很重要的概念,管程其實指的是管理共享變量以及管理共享變量的操作過程。有點扮演中介的意思,管程管理一堆對象,多個線程同一時候只能有一個線程來訪問這些東西。

管程可以看做一個軟件模塊,它是將共享的變量和對于這些共享變量的操作封裝起來,形成一個具有一定接口的功能模塊,進程可以調(diào)用管程來實現(xiàn)進程級別的并發(fā)控制。

進程只能互斥的使用管程,即當一個進程使用管程時,另一個進程必須等待。當一個進程使用完管程后,它必須釋放管程并喚醒等待管程的某一個進程。

管程解決互斥問題相對簡單,把共享變量以及共享變量的操作都封裝在一個類中

2aa786c4-8ecb-11eb-8b86-12bb97331649.png

當線程A和線程B需要獲取共享變量count時,就需要調(diào)用get和set方法,而get和set方法則保證互斥性,保證每次只能有一個線程訪問。

生活中舉例管程比如鏈家店長分配給每一個中介管理一部分二手房源,多個客戶通過中介進行房屋買賣。

中介 就是管程。

多個二手房源被一個中介管理中,就是一個管程管理著多個系統(tǒng)資源。

多個客戶就相當于多個線程。

Synchronzied的底層原理

對象頭解析

我們知道在Java的JVM內(nèi)存區(qū)域[3]中一個對象在堆區(qū)創(chuàng)建,創(chuàng)建后的對象由三部分組成。

2ae9941a-8ecb-11eb-8b86-12bb97331649.png

這三部分功能如下:

填充數(shù)據(jù):由于虛擬機要求對象起始地址必須是8字節(jié)的整數(shù)倍。填充數(shù)據(jù)不是必須存在的,僅僅是為了字節(jié)對齊。

實例變量:存放類的屬性數(shù)據(jù)信息,包括父類的屬性信息,這部分內(nèi)存按4字節(jié)對齊。

對象頭:主要包括兩部分Klass Point跟Mark Word

Klass Point(類型指針):是對象指向它的類元數(shù)據(jù)的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例。

Mark Word(標記字段):這一部分用于儲存對象自身的運行時數(shù)據(jù),如哈希碼,GC分代年齡,鎖狀態(tài)標志,鎖指針等,這部分數(shù)據(jù)在32bit和64bit的虛擬機中大小分別為32bit和64bit,考慮到虛擬機的空間效率,Mark Word被設計成一個非固定的數(shù)據(jù)結(jié)構(gòu)以便在極小的空間中存儲盡量多的信息,它會根據(jù)對象的狀態(tài)復用自己的存儲空間(跟ConcurrentHashMap里的標志位類似),詳細情況如下圖:

Mark Word狀態(tài)表示位如下:

2af13148-8ecb-11eb-8b86-12bb97331649.png

synchronized不論是修飾方法還是代碼塊,都是通過持有修飾對象的鎖來實現(xiàn)同步,synchronized鎖對象是存在對象頭Mark Word。其中輕量級鎖和偏向鎖是Java6對synchronized鎖進行優(yōu)化后新增加的,這里我們主要分析一下重量級鎖也就是通常說synchronized的對象鎖,鎖標識位為10,其中指針指向的是monitor對象(也稱為管程或監(jiān)視器鎖)的起始地址。每個對象都存在著一個monitor[4]與之關聯(lián)。

2b297c10-8ecb-11eb-8b86-12bb97331649.png


匯編查看

分析對象的monitor前我們先通過反匯編看下同步方法跟同步方法塊在匯編語言級別是什么樣的指令。

publicclassSynchronizedTest{ publicsynchronizedvoiddoSth(){ System.out.println("HelloWorld"); } publicvoiddoSth1(){ synchronized(SynchronizedTest.class){ System.out.println("HelloWorld"); } } }

javac SynchronizedTest .java然后javap -c SynchronizedTest反編譯后看匯編指令如下:

publicsynchronizedvoiddoSth(); descriptor:()V flags:ACC_PUBLIC,ACC_SYNCHRONIZED//這是重點方法鎖Code: stack=2,locals=1,args_size=10:getstatic#2 3:ldc#3 5:invokevirtual#4 8:returnpublicvoiddoSth1(); descriptor:()V flags:ACC_PUBLIC Code: stack=2,locals=3,args_size=10:ldc#5 2:dup 3:astore_1 4:monitorenter//進入同步方法5:getstatic#2 8:ldc#3 10:invokevirtual#4 13:aload_1 14:monitorexit//正常時退出同步方法15:goto2318:astore_2 19:aload_1 20:monitorexit//異常時退出同步方法21:aload_2 22:athrow 23:return

我們可以看到Java編譯器為我們生成的字節(jié)碼。在對于doSth和doSth1的處理上稍有不同。也就是說。JVM對于同步方法和同步代碼塊的處理方式不同。對于同步方法,JVM采用ACC_SYNCHRONIZED標記符來實現(xiàn)同步。對于同步代碼塊。JVM采用monitorenter、monitorexit兩個指令來實現(xiàn)同步。

ACC_SYNCHRONIZED

方法級的同步是隱式的。同步方法的常量池中會有一個ACC_SYNCHRONIZED標志。當某個線程要訪問某個方法的時候,會檢查是否有ACC_SYNCHRONIZED,如果有設置,則需要先獲得監(jiān)視器鎖,然后開始執(zhí)行方法,方法執(zhí)行之后再釋放監(jiān)視器鎖。這時如果其他線程來請求執(zhí)行方法,會因為無法獲得監(jiān)視器鎖而被阻斷住。值得注意的是,如果在方法執(zhí)行過程中,發(fā)生了異常,并且方法內(nèi)部并沒有處理該異常,那么在異常被拋到方法外面之前監(jiān)視器鎖會被自動釋放。

monitorenter跟monitorexit

可以把執(zhí)行monitorenter指令理解為加鎖,執(zhí)行monitorexit理解為釋放鎖。每個對象維護著一個記錄著被鎖次數(shù)的計數(shù)器。未被鎖定的對象的該計數(shù)器為0,當一個線程獲得鎖(執(zhí)行monitorenter)后,該計數(shù)器自增變?yōu)?1 ,當同一個線程再次獲得該對象的鎖的時候,計數(shù)器再次自增。當同一個線程釋放鎖(執(zhí)行monitorexit指令)的時候,計數(shù)器再自減。當計數(shù)器為0的時候。鎖將被釋放,其他線程便可以獲得鎖。

結(jié)論:同步方法和同步代碼塊底層都是通過monitor來實現(xiàn)同步的。兩者區(qū)別:同步方式是通過方法中的access_flags中設置ACC_SYNCHRONIZED標志來實現(xiàn),同步代碼塊是通過monitorenter和monitorexit來實現(xiàn)。

monitor解析

每個對象都與一個monitor相關聯(lián),而monitor可以被線程擁有或釋放,在Java虛擬機(HotSpot)中,monitor是由ObjectMonitor實現(xiàn)的,其主要數(shù)據(jù)結(jié)構(gòu)如下(位于HotSpot虛擬機源碼ObjectMonitor.hpp文件,C++實現(xiàn)的)。

ObjectMonitor(){ _count=0;//記錄數(shù)_recursions=0;//鎖的重入次數(shù)_owner=NULL;//指向持有ObjectMonitor對象的線程_WaitSet=NULL;//調(diào)用wait后,線程會被加入到_WaitSet_EntryList=NULL;//等待獲取鎖的線程,會被加入到該列表}

monitor運行圖如下:

2b7a949c-8ecb-11eb-8b86-12bb97331649.png

對于一個synchronized修飾的方法(代碼塊)來說:

當多個線程同時訪問該方法,那么這些線程會先被放進_EntryList隊列,此時線程處于blocked狀態(tài)

當一個線程獲取到了對象的monitor后,那么就可以進入running狀態(tài),執(zhí)行方法塊,此時,ObjectMonitor對象的_owner指向當前線程,_count加1表示當前對象鎖被一個線程獲取。

當running狀態(tài)的線程調(diào)用wait()方法,那么當前線程釋放monitor對象,進入waiting狀態(tài),ObjectMonitor對象的_owner變?yōu)閚ull,_count減1,同時線程進入_WaitSet隊列,直到有線程調(diào)用notify()方法喚醒該線程,則該線程進入_EntryList隊列,競爭到鎖再進入_owner區(qū)。

如果當前線程執(zhí)行完畢,那么也釋放monitor對象,ObjectMonitor對象的_owner變?yōu)閚ull,_count減1。

因為監(jiān)視器鎖(monitor)是依賴于底層的操作系統(tǒng)的Mutex Lock來實現(xiàn)的,而操作系統(tǒng)實現(xiàn)線程之間的切換時需要從用戶態(tài)轉(zhuǎn)換到核心態(tài)(具體可看CXUAN寫的OS哦),這個狀態(tài)之間的轉(zhuǎn)換需要相對比較長的時間,時間成本相對較高,這也是早期的synchronized效率低的原因。慶幸在Java 6之后Java官方對從JVM層面對synchronized較大優(yōu)化最終提升顯著,Java 6之后,為了減少獲得鎖和釋放鎖所帶來的性能消耗,引入了鎖升級的概念。

鎖升級

synchronized鎖有四種狀態(tài),無鎖、偏向鎖、輕量級鎖、重量級鎖。這幾個狀態(tài)會隨著競爭狀態(tài)逐漸升級,鎖可以升級但不能降級,但是偏向鎖狀態(tài)可以被重置為無鎖狀態(tài)。科學性的說這些鎖之前我們先看個簡單通俗的例子來加深印象。

通俗說各種鎖

偏向鎖、輕量級鎖和重量級鎖之間的關系,首先打個比方[5]:假設現(xiàn)在廁所只有一個位置,每個使用者都有打開門鎖的鑰匙。必須打開門鎖才能使用廁所。其中小明、小紅理解為兩個線程,上廁所理解為執(zhí)行同步代碼,門鎖理解為同步代碼的鎖

小明今天吃壞了東西需要反復去廁所,如果小明每次都要開鎖就很耽誤時間,于是門鎖將小明的臉記錄下來(假設那個鎖是智能鎖),下次小明再來的時候門鎖會自動識別出是小明來了,然后自動開鎖,這樣就省去了小明拿鑰匙開門的過程,此時門鎖就是偏向鎖,也可以理解為偏向小明的鎖。

接下來,小紅又去上廁所,試圖將廁所的門鎖設置為偏向自己的偏向鎖,于是發(fā)現(xiàn)門鎖無法偏向自己,因為此時門鎖已是偏向小明的偏向鎖。于是小紅很生氣,要求門鎖撤銷對小明的偏向,當然,小明也不同意門鎖偏向小紅。于是等小明用完廁所之后,門鎖撤銷了對任何人的偏向(只要出現(xiàn)競爭的情況,就會撤銷偏向鎖)。這個過程就是撤銷偏向鎖。此時門鎖升級為輕量級鎖。

等小明出來以后,輕量級鎖正式生效 。下一次小明和小紅同時來廁所,誰跑的快誰先走到門前,開門后將門鎖拿進廁所,并將門鎖打開以后拿進廁所里,將門反鎖,于是在門外原來放門鎖的位置放置了一個有人的標志(這個標識可以理解為指向門鎖的指針,或者理解為作為鎖的Java對象頭的Mark Word值),這時,小紅看到有人以后很著急,催著里面的人出來時馬上進去,于是不斷的來敲門,問小明什么時候出來。這個過程就是自旋。

反復敲了幾次以后,小明受不了了,對小紅喊話,說你別敲了,等我用完廁所我告訴你,于是小紅去一邊等著(線性阻塞)。此時門鎖升級為重量級鎖。升級為重量級鎖的后果就是,小紅不再反復敲門,小明在上完廁所以后必須告訴小紅一聲,否則小紅就會一直等著。

結(jié)論:

偏向鎖在只有一個人上廁所時非常高效,省去了開門的過程。輕量級鎖在有多人上廁所但是每個人使用的特別快的時候,比較高效,因為會出現(xiàn)這種現(xiàn)象,小紅敲門的時候正好趕上小明出來,這樣就省得小明出來告訴小紅以后小紅才能進去,但是這樣可能會出現(xiàn)小紅敲門失敗的情況(就是敲門時小明還沒用完)。重量級鎖相比與輕量級鎖的多了一步小明呼喚小紅的步驟,但是卻省掉了小紅反復去敲門的過程,但是能保證小紅去廁所時廁所一定是沒人的。

偏向鎖

經(jīng)過HotSpot的作者大量的研究發(fā)現(xiàn)大多數(shù)時候是不存在鎖競爭的,經(jīng)常是一個線程多次獲得同一個鎖,因此如果每次都要競爭鎖會增大很多沒有必要付出的代價,為了降低獲取鎖的代價,才引入的偏向鎖。核心思想:

如果一個線程獲得了鎖,那么鎖就進入偏向模式,此時Mark Word的結(jié)構(gòu)也變?yōu)槠蜴i結(jié)構(gòu),當這個線程再次請求鎖時,無需再做任何同步操作,即獲取鎖的過程,這樣就省去了大量有關鎖申請的操作,從而也就提供程序的性能。所以,對于沒有鎖競爭的場合,偏向鎖有很好的優(yōu)化效果,畢竟極有可能連續(xù)多次是同一個線程申請相同的鎖。但是對于鎖競爭比較激烈的場合,偏向鎖就失效了,因為這樣場合極有可能每次申請鎖的線程都是不相同的,因此這種場合下不應該使用偏向鎖,否則會得不償失,需要注意的是,偏向鎖失敗后,并不會立即膨脹為重量級鎖,而是先升級為輕量級鎖。

具體流程:當線程1訪問代碼塊并獲取鎖對象時,會在java對象頭和棧幀中記錄偏向的鎖的threadID,因為偏向鎖不會主動釋放鎖,因此以后線程1再次獲取鎖的時候,需要比較當前線程的threadID和Java對象頭中的threadID是否一致,如果一致(還是線程1獲取鎖對象),則無需使用CAS來加鎖、解鎖;如果不一致(其他線程,如線程2要競爭鎖對象,而偏向鎖不會主動釋放因此還是存儲的線程1的threadID),那么需要查看Java對象頭中記錄的線程1是否存活,如果沒有存活,那么鎖對象被重置為無鎖狀態(tài),其它線程(線程2)可以競爭將其設置為偏向鎖;如果存活,那么立刻查找該線程(線程1)的棧幀信息,如果還是需要繼續(xù)持有這個鎖對象,那么暫停當前線程1,撤銷偏向鎖,升級為輕量級鎖,如果線程1不再使用該鎖對象,那么將鎖對象狀態(tài)設為無鎖狀態(tài),重新偏向新的線程。

輕量級鎖

輕量級鎖考慮的是競爭鎖對象的線程不多,而且線程持有鎖的時間也不長的情景。因為阻塞線程需要高昂的耗時實現(xiàn)CPU從用戶態(tài)轉(zhuǎn)到內(nèi)核態(tài)的切換,如果剛剛阻塞不久這個鎖就被釋放了,那這個代價就有點得不償失了,因此這個時候就干脆不阻塞這個線程,讓它自旋這等待鎖釋放。

「原理跟升級」:線程1獲取輕量級鎖時會先把鎖對象的對象頭MarkWord復制一份到線程1的棧幀中創(chuàng)建的用于存儲鎖記錄的空間(稱為DisplacedMarkWord),然后使用CAS把對象頭中的內(nèi)容替換為線程1存儲的鎖記錄(DisplacedMarkWord)的地址;

如果在線程1復制對象頭的同時(在線程1CAS之前),線程2也準備獲取鎖,復制了對象頭到線程2的鎖記錄空間中,但是在線程2CAS的時候,發(fā)現(xiàn)線程1已經(jīng)把對象頭換了,「線程2的CAS失敗,那么線程2就嘗試使用自旋鎖來等待線程1釋放鎖」。自旋鎖簡單來說就是讓線程2在循環(huán)中不斷CAS嘗試獲得鎖對象。

但是如果自旋的「時間太長」也不行,因為自旋是要消耗CPU的,因此「自旋的次數(shù)是有限制」的,比如10次或者100次,如果自旋次數(shù)到了線程1還沒有釋放鎖,或者線程1還在執(zhí)行,線程2還在自旋等待,那么這個時候輕量級鎖就會膨脹為重量級鎖。重量級鎖把除了擁有鎖的線程都阻塞,防止CPU空轉(zhuǎn)。

2c079b44-8ecb-11eb-8b86-12bb97331649.png

鎖消除

消除鎖是虛擬機另外一種鎖的優(yōu)化,這種優(yōu)化更徹底,Java虛擬機在JIT編譯時通過對運行上下文的掃描,去除不可能存在共享資源競爭的鎖,通過這種方式消,除沒有必要的鎖,可以節(jié)省毫無意義的請求鎖時間,我們知道StringBuffer是線程安全的,里面包含鎖的存在,但是如果我們在函數(shù)內(nèi)部使用StringBuffer那么代碼會在JIT后會自動將鎖釋放掉哦。

對比如下:

鎖狀態(tài) 優(yōu)點 缺點 適用場景
偏向鎖 加鎖解鎖無需額外消耗,跟非同步方法時間相差納秒級別 如果競爭線程多,會帶來額外的鎖撤銷的消耗 基本沒有其他線程競爭的同步場景
輕量級鎖 競爭的線程不會阻塞而是在自旋,可提高程序響應速度 如果一直無法獲得會自旋消耗CPU 少量線程競爭,持有鎖時間不長,追求響應速度
重量級鎖 線程競爭不會導致CPU自旋跟消耗CPU資源 線程阻塞,響應時間長 很多線程競爭鎖,切鎖持有時間長,追求吞吐量時候

PS:ReentrantLock底層實現(xiàn)依賴于特殊的CPU指令,比如發(fā)送lock指令和unlock指令,不需要用戶態(tài)和內(nèi)核態(tài)的切換,所以效率高。而synchronized底層由監(jiān)視器鎖(monitor)是依賴于底層的操作系統(tǒng)的Mutex Lock需要用戶態(tài)和內(nèi)核態(tài)的切換,所以效率會低一些。

鎖升級流程圖

原文標題:由淺入深逐步了解 Synchronized

文章出處:【微信公眾號:FPGA之家】歡迎添加關注!文章轉(zhuǎn)載請注明出處。

責任編輯:haq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 軟件
    +關注

    關注

    69

    文章

    4570

    瀏覽量

    86697
  • 編程
    +關注

    關注

    88

    文章

    3521

    瀏覽量

    93268

原文標題:由淺入深逐步了解 Synchronized

文章出處:【微信號:zhuyandz,微信公眾號:FPGA之家】歡迎添加關注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關推薦

    java實現(xiàn)多線程的幾種方式

    Java實現(xiàn)多線程的幾種方式 多線程是指程序中包含了兩個或以上的線程,每個線程都可以并行執(zhí)行不同的任務或操作。
    的頭像 發(fā)表于 03-14 16:55 ?435次閱讀

    并發(fā)情況如何實現(xiàn)加鎖來保證數(shù)據(jù)一致性

    ReentrantLock(可重入鎖),指的是一個線程再次對已持有的鎖保護的臨界資源時,重入請求將會成功。 簡單的與我們常用Synchronized 進行比較。
    的頭像 發(fā)表于 12-21 10:22 ?501次閱讀
    <b class='flag-5'>并發(fā)</b>情況如何實現(xiàn)加鎖來保證數(shù)據(jù)一致性

    java redis鎖處理并發(fā)代碼

    并發(fā)編程中,一個常見的問題是如何確保多個線程安全地訪問共享資源,避免產(chǎn)生競態(tài)條件和數(shù)據(jù)異常。而Redis作為一種高性能的內(nèi)存數(shù)據(jù)庫,可以提供分布式鎖的功能,通過Redis鎖,我們可以有效地解決
    的頭像 發(fā)表于 12-04 11:04 ?763次閱讀

    mfc多線程編程實例

    (圖形用戶界面)應用程序的開發(fā)。在這篇文章中,我們將重點介紹MFC中的多線程編程。 多線程編程在軟件開發(fā)中非常重要,它可以實現(xiàn)程序的并發(fā)執(zhí)行
    的頭像 發(fā)表于 12-01 14:29 ?1143次閱讀

    核心線程數(shù)和最大線程數(shù)怎么設置

    核心線程數(shù)和最大線程數(shù)是Java線程池中重要的參數(shù),用來控制線程中線程的數(shù)量和行為。正確地設置
    的頭像 發(fā)表于 12-01 13:50 ?7454次閱讀

    java常用的包有哪些

    Java是一種面向?qū)ο蟮母呒?b class='flag-5'>編程語言,它具有平臺無關性和可擴展性。Java中有很多常用的包,這些包提供了豐富的類庫和工具,用于開發(fā)各種類型的應用程序。下面是
    的頭像 發(fā)表于 11-22 15:10 ?1092次閱讀

    線程如何保證數(shù)據(jù)的同步

    線程編程是一種并發(fā)編程的方法,意味著程序中同時運行多個線程,每個線程可獨立執(zhí)行不同的任務,共享
    的頭像 發(fā)表于 11-17 14:22 ?891次閱讀

    什么是虛擬線程?虛擬線程到底是做什么用的呢?

    虛擬線程是在Java并發(fā)領域添加的一個新概念,那么虛擬線程到底是做什么用的呢?
    的頭像 發(fā)表于 10-29 10:23 ?2922次閱讀
    什么是虛擬<b class='flag-5'>線程</b>?虛擬<b class='flag-5'>線程</b>到底是做什么用的呢?

    Java中的線程池包括哪些

    線程池是用來統(tǒng)一管理線程的,在 Java 中創(chuàng)建和銷毀線程都是一件消耗資源的事情,線程池可以重復使用線程
    的頭像 發(fā)表于 10-11 15:33 ?730次閱讀
    <b class='flag-5'>Java</b>中的<b class='flag-5'>線程</b>池包括哪些

    synchronized的鎖膨脹

    初識 synchronized 可以加在方法和類上面,作用于類和對象。下面代碼中列出了 synchronized用法。 public class SynchronizedTest
    的頭像 發(fā)表于 10-10 16:58 ?390次閱讀
    <b class='flag-5'>synchronized</b>的鎖膨脹

    synchronized 的幾種錯誤用法

    synchronized 在我們平常工作中也是挺常用的, 對于擺脫多線程問題很有幫助。但是如果synchronized被錯誤使用時,可能會給我們帶來很多麻煩。 在本文中,我們將討論與
    的頭像 發(fā)表于 10-09 10:25 ?493次閱讀

    Java線程用法

    本文將介紹一下Java線程用法。 基礎介紹 什么是多線程 指的是在一個進程中同時運行多個線程,每個
    的頭像 發(fā)表于 09-30 17:07 ?843次閱讀

    ThreadLocal的定義、用法及優(yōu)點

    ThreadLocal的定義、用法及其優(yōu)點。 ThreadLocal是Java中一個用來實現(xiàn)線程封閉技術的類。它提供了一個本地線程變量,可以在多線程
    的頭像 發(fā)表于 09-30 10:14 ?878次閱讀
    ThreadLocal的定義、<b class='flag-5'>用法</b>及優(yōu)點

    Java枚舉的特點及用法

    Java 枚舉出現(xiàn)之前,通常會使用常量類來表示一組固定的常量值,直到Java 1.5之后推出了枚舉,那么枚舉類型有哪些特點,它比常量類又好在哪里呢。 本文將分析一下枚舉的特點及用法。 1.
    的頭像 發(fā)表于 09-30 10:02 ?1149次閱讀

    HarmonyOS使用多線程并發(fā)能力開發(fā)

    一、多線程并發(fā)概述 1、簡介 并發(fā)模型是用來實現(xiàn)不同應用場景中并發(fā)任務的編程模型,常見的并發(fā)模型
    發(fā)表于 09-25 15:23