欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java多線程的同步優(yōu)化的6種方案

 更新時(shí)間:2021年05月26日 11:58:34   作者:卜大爺  
大家使用多線程無(wú)非是為了提高性能,在Java中,有多線程并發(fā)時(shí),我們可以使用多線程同步的方式來(lái)解決內(nèi)存一致性的問(wèn)題。本文就詳細(xì)的介紹了Java多線程同步優(yōu)化,感興趣的可以了解一下

概述

處理器上的寄存器的讀寫的速度比內(nèi)存快幾個(gè)數(shù)量級(jí),為了解決這種速度矛盾,在它們之間加入了高速緩存。

加入高速緩存帶來(lái)了一個(gè)新的問(wèn)題:緩存一致性。如果多個(gè)緩存共享同一塊主內(nèi)存區(qū)域,那么多個(gè)緩存的數(shù)據(jù)可能會(huì)不一致,需要一些協(xié)議來(lái)解決這個(gè)問(wèn)題。

在Java內(nèi)存模型中,分為主內(nèi)存和線程工作內(nèi)存,線程使用共享數(shù)據(jù)時(shí),先從主內(nèi)存中拷貝數(shù)據(jù)到工作內(nèi)存,使用完成之后再寫入主內(nèi)存中。

在Java中,有多線程并發(fā)時(shí),我們可以使用多線程同步的方式來(lái)解決內(nèi)存一致性的問(wèn)題。通常我們可以在程序中添加同步鎖來(lái)保障數(shù)據(jù)的安全訪問(wèn),但是也經(jīng)常會(huì)帶來(lái)一些同步性能問(wèn)題,那么本章將針對(duì)常見的同步問(wèn)題給出了一些優(yōu)化方案。

讀寫鎖

在多線程操作下,如果我們的某些數(shù)據(jù)經(jīng)常被讀取操作,但非常少的時(shí)機(jī)被寫入操作。這時(shí),如果我們使用synchronized等同步方式,性能會(huì)非常低。

這種場(chǎng)景下,我們應(yīng)該使用讀寫鎖來(lái)進(jìn)行優(yōu)化。

讀寫鎖的特點(diǎn):

  • 讀寫鎖維護(hù)一對(duì)鎖,讀鎖和寫鎖。
  • 可以共享讀,但只能一個(gè)寫。
  • 讀讀不互斥,讀寫互斥,寫寫互斥。

某些特定的場(chǎng)景,使用讀寫鎖會(huì)極大的提高多線程并發(fā)操作的效率。因?yàn)?,讀寫鎖中,讀鎖不是排它鎖,所以可以并發(fā)執(zhí)行,可以非常顯著的提高讀取效率;只有在寫鎖時(shí),是排它鎖,這時(shí)需要等待寫鎖的釋放。

ReetrantReadWriteLock

ReadWriteLock接口

Java并發(fā)包中ReadWriteLock是一個(gè)接口,抽象了讀寫鎖方法:

public interface ReadWriteLock {
    /**
     * Returns the lock used for reading.
     *
     * @return the lock used for reading
     */
    Lock readLock();

    /**
     * Returns the lock used for writing.
     *
     * @return the lock used for writing
     */
    Lock writeLock();
}

ReadWriteLock管理一組鎖,一個(gè)是只讀的鎖,一個(gè)是寫鎖。

ReetrantReadWriteLock類

Java并發(fā)庫(kù)中ReetrantReadWriteLock實(shí)現(xiàn)了ReadWriteLock接口并添加了可重入的特性。

1. ReetrantReadWriteLock獲取鎖順序有兩種模式:

  • 非公平模式(默認(rèn)):非公平鎖主張競(jìng)爭(zhēng)獲取,可能會(huì)延緩一個(gè)或多個(gè)讀或?qū)懢€程,但是會(huì)比公平鎖有更高的吞吐量。
  • 公平模式:當(dāng)以公平模式初始化時(shí),線程將會(huì)以隊(duì)列的順序獲取鎖。

2. 可重入

ReetrantReadWriteLock鎖是可重入的,當(dāng)然一個(gè)線程獲取多少次鎖,就必須釋放多少次鎖。

  • 讀線程獲取讀鎖之后能夠再次獲取讀鎖。
  • 寫線程獲取寫鎖之后能再次獲取寫鎖,也可以獲取讀鎖。

3. 鎖降級(jí)

在讀寫鎖中,鎖降級(jí):從寫鎖變成讀鎖;鎖升級(jí):從讀鎖變成寫鎖。

  • ReentrantReadWriteLock是不支持鎖升級(jí)的,也就是當(dāng)一個(gè)線程持有了讀鎖,當(dāng)該線程再次使用寫鎖時(shí),是不可以的。如果一個(gè)線程持有了讀鎖,則在獲取寫鎖之前,一定要先釋放讀鎖。
  • ReentrantReadWriteLock支持鎖降級(jí)的,也就是如果當(dāng)前線程是寫鎖的持有者,并保持獲得寫鎖的狀態(tài),同時(shí)又獲取到讀鎖,然后釋放寫鎖的過(guò)程。按照獲取寫鎖、獲取讀鎖、再釋放寫鎖的順序,即寫鎖能夠降級(jí)為讀鎖。

讀寫鎖狀態(tài)的設(shè)計(jì)

讀寫鎖的狀態(tài)是用一個(gè)int值來(lái)表示的。state(int32位)字段分成高16位與低16位,其中高16位表示讀鎖個(gè)數(shù),低16位表示寫鎖個(gè)數(shù)。

例如,當(dāng)前一個(gè)線程獲取到了寫鎖,并且重入了兩次,因此低16位是3,并且該線程又獲取了讀鎖,并且重入了一次,所以高16位是2,當(dāng)寫鎖被獲取時(shí)如果讀鎖不為0那么讀鎖一定是獲取寫鎖的這個(gè)線程。

寫時(shí)復(fù)制

寫時(shí)復(fù)制(Copy-on-write,簡(jiǎn)稱COW)是一種計(jì)算機(jī)程序設(shè)計(jì)領(lǐng)域的優(yōu)化策略。其核心思想是,如果有多個(gè)調(diào)用者同時(shí)要求相同資源,他們會(huì)共同獲取相同的指針指向相同的資源,直到某個(gè)調(diào)用者試圖修改資源的內(nèi)容時(shí),系統(tǒng)才會(huì)真正復(fù)制一份專用副本給該調(diào)用者,而其他調(diào)用者所見到的最初的資源仍然保持不變。這過(guò)程對(duì)其他的調(diào)用者都是透明的。此作法主要的優(yōu)點(diǎn)是如果調(diào)用者沒(méi)有修改該資源,就不會(huì)有副本被創(chuàng)建,因此多個(gè)調(diào)用者只是讀取操作時(shí)可以共享同一份資源。

在Java中,Copy on Write這種機(jī)制通常用在集合上,在并發(fā)訪問(wèn)的情景下,當(dāng)需要修改JAVA中Containers的元素時(shí),不直接修改該容器,而是先復(fù)制一份副本,在副本上進(jìn)行修改。修改完成之后,將指向原來(lái)容器的引用指向新的容器(副本容器)。

寫時(shí)復(fù)制的特點(diǎn)

  • 由于不會(huì)修改原始容器,只修改副本容器。因此,可以對(duì)原始容器進(jìn)行并發(fā)地讀。其次,實(shí)現(xiàn)了讀操作與寫操作的分離,讀操作發(fā)生在原始容器上,寫操作發(fā)生在副本容器上。
  • 數(shù)據(jù)一致性問(wèn)題:因?yàn)樾薷牟僮靼l(fā)生在副本上,讀操作的線程可能不會(huì)立即讀取到新修改的數(shù)據(jù)內(nèi)容,但最終修改操作會(huì)完成并更新容器,因此這是最終一致性。
  • CopyOnWrite容器適用于讀多寫少的場(chǎng)景。寫操作時(shí),需要復(fù)制一個(gè)容器,會(huì)造成很大的內(nèi)存開銷。
  • 不適合于數(shù)據(jù)的強(qiáng)一致性場(chǎng)合。若要求數(shù)據(jù)修改之后立即能被讀到,則不能用寫時(shí)復(fù)制技術(shù)。因?yàn)樗亲罱K一致性。

Java寫時(shí)復(fù)制容器類

JDK中提供了CopyOnWriteArrayList類和CopyOnWriteArraySet類,實(shí)現(xiàn)了寫時(shí)復(fù)制。

減小鎖的粒度

如果我們?cè)谝粋€(gè)大的數(shù)據(jù)操作類里面,大量使用了鎖,并且還是同一個(gè)鎖,這時(shí),我們的多線程同步效率就會(huì)變得非常低。

我們可以將數(shù)據(jù)按照不同的類型及應(yīng)用場(chǎng)景進(jìn)行分割,然后用不同的鎖進(jìn)行同步,這樣,不同的場(chǎng)景下就不會(huì)產(chǎn)生排它鎖的沖突問(wèn)題,可以大大提高同步的效率。

該方案簡(jiǎn)單來(lái)說(shuō)就是將一個(gè)大鎖,分割成多個(gè)小鎖,這樣就能顯著的提高多線程并發(fā)執(zhí)行的效率。

減小鎖的占有時(shí)間

如果在一個(gè)較大的方法中,我們直接給該方法加了一個(gè)鎖,但是我們需要同步的地方只是該方法中的一行操作代碼,這樣就是很糟糕的同步使用方式了。

我們可以將鎖細(xì)化到使用它的代碼行上,而不是整個(gè)函數(shù)都加鎖,這樣鎖的持有時(shí)間就會(huì)變少,從而提高了多線程同步的性能。

該方案是將同步塊的代碼范圍減小,從而降低鎖的持有時(shí)間,達(dá)到優(yōu)化多線程同步性能的目的。

鎖粗化

雖然說(shuō),減少鎖的占有時(shí)間可以提高性能,但是有時(shí)候,這種方式并不適用。

例如,一個(gè)循環(huán)中,我們?cè)谘h(huán)體中,使用了鎖,這樣反而會(huì)降低性能,這時(shí)我們應(yīng)該在循環(huán)開始之前加鎖,結(jié)束之后釋放,也就是將鎖粗化。

這是為什么呢?

這是因?yàn)椋l繁的對(duì)鎖進(jìn)行請(qǐng)求、釋放、狀態(tài)修改等操作,會(huì)造成大量系統(tǒng)資源的消耗,從而降低性能。

ThreadLocal

同步效率低,是因?yàn)槎嗑€程同步等待造成的,那么我們可以換一個(gè)思路,如果讓每個(gè)線程都持有一份數(shù)據(jù),那這樣就不會(huì)存在競(jìng)爭(zhēng)的問(wèn)題了,也就不需要同步鎖了。這樣就會(huì)很大程度上提高多線程并發(fā)的性能。

關(guān)于ThreadLocal相關(guān)實(shí)現(xiàn)原理及使用可以參考之前的文章《ThreadLocal線程本地對(duì)象原理分析》。

總結(jié)

Java中可以使用鎖來(lái)解決多線程的同步問(wèn)題,保障了數(shù)據(jù)的一致性,但也會(huì)代理很多問(wèn)題,本章總結(jié)了多線程同步的幾種優(yōu)化方案:

  • 某些特定的場(chǎng)景(大多是讀多、寫少的場(chǎng)景),使用讀寫鎖會(huì)極大的提高多線程并發(fā)操作的效率。因?yàn)?,讀寫鎖中,讀鎖不是排它鎖,所以可以并發(fā)執(zhí)行,可以非常顯著的提高讀取效率;只有在寫鎖時(shí),是排它鎖,這時(shí)需要等待寫鎖的釋放。
  • Java并發(fā)庫(kù)中ReetrantReadWriteLock實(shí)現(xiàn)了ReadWriteLock接口并添加了可重入的特性。
  • 寫時(shí)復(fù)制機(jī)制可以顯著提高并發(fā)效率,在并發(fā)訪問(wèn)的情景下,當(dāng)需要修改JAVA中Containers的元素時(shí),不直接修改該容器,而是先復(fù)制一份副本,在副本上進(jìn)行修改。修改完成之后,將指向原來(lái)容器的引用指向新的容器(副本容器)。CopyOnWrite容器適用于讀多寫少的場(chǎng)景。寫操作時(shí),需要復(fù)制一個(gè)容器,會(huì)造成很大的內(nèi)存開銷。
  • 通過(guò)減小鎖的粒度,來(lái)提高同步效率。
  • 減小鎖的占有時(shí)間是指,通過(guò)將同步塊的代碼范圍減小,從而降低鎖的持有時(shí)間,達(dá)到優(yōu)化多線程同步性能的目的。
  • 有時(shí),大量的鎖和鎖狀態(tài)修改會(huì)造成系統(tǒng)資源的消耗,我們可以通過(guò)鎖粗化來(lái)優(yōu)化性能。
  • 我們可以換一個(gè)思路,使用ThreadLocal來(lái)提高多線程并發(fā)的性能。

到此這篇關(guān)于Java多線程的同步優(yōu)化的6種方案的文章就介紹到這了,更多相關(guān)Java多線程同步優(yōu)化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java isPalindrome方法在密碼驗(yàn)證中的應(yīng)用

    java isPalindrome方法在密碼驗(yàn)證中的應(yīng)用

    這篇文章主要為大家介紹了java isPalindrome方法在密碼驗(yàn)證中的簡(jiǎn)單應(yīng)用技巧,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • 如何使用IDEA從SVN服務(wù)端檢出項(xiàng)目

    如何使用IDEA從SVN服務(wù)端檢出項(xiàng)目

    這篇文章主要介紹了如何使用IDEA從SVN服務(wù)端檢出項(xiàng)目問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • 聊聊Spring——AOP詳解(AOP概覽)

    聊聊Spring——AOP詳解(AOP概覽)

    這篇文章主要介紹了Spring——AOP詳解(AOP概覽),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java構(gòu)造函數(shù)與普通函數(shù)用法詳解

    Java構(gòu)造函數(shù)與普通函數(shù)用法詳解

    本篇文章給大家詳細(xì)講述了Java構(gòu)造函數(shù)與普通函數(shù)用法以及相關(guān)知識(shí)點(diǎn),對(duì)此有興趣的朋友可以參考學(xué)習(xí)下。
    2018-03-03
  • java實(shí)現(xiàn)簡(jiǎn)單的猜數(shù)字小游戲

    java實(shí)現(xiàn)簡(jiǎn)單的猜數(shù)字小游戲

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)單猜數(shù)字小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • SpringDataJPA實(shí)體類關(guān)系映射配置方式

    SpringDataJPA實(shí)體類關(guān)系映射配置方式

    這篇文章主要介紹了SpringDataJPA實(shí)體類關(guān)系映射配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • SpringBoot快速整合RabbitMq小案例(使用步驟)

    SpringBoot快速整合RabbitMq小案例(使用步驟)

    這篇文章主要介紹了SpringBoot快速整合RabbitMq小案例,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • Spring定時(shí)任務(wù)@Scheduled注解(cron表達(dá)式fixedRate?fixedDelay)

    Spring定時(shí)任務(wù)@Scheduled注解(cron表達(dá)式fixedRate?fixedDelay)

    這篇文章主要為大家介紹了Spring定時(shí)任務(wù)@Scheduled注解(cron表達(dá)式fixedRate?fixedDelay)使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • java 多態(tài)性詳解及簡(jiǎn)單實(shí)例

    java 多態(tài)性詳解及簡(jiǎn)單實(shí)例

    這篇文章主要介紹了java 多態(tài)性詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • Java 整合模板徹底解決ssm配置難題

    Java 整合模板徹底解決ssm配置難題

    SSM框架是spring MVC ,spring和mybatis框架的整合,是標(biāo)準(zhǔn)的MVC模式,將整個(gè)系統(tǒng)劃分為表現(xiàn)層,controller層,service層,DAO層四層,使用spring MVC負(fù)責(zé)請(qǐng)求的轉(zhuǎn)發(fā)和視圖管理,spring實(shí)現(xiàn)業(yè)務(wù)對(duì)象管理,mybatis作為數(shù)據(jù)對(duì)象的持久化引擎
    2021-10-10

最新評(píng)論