真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Java中的線(xiàn)程安全性介紹-創(chuàng)新互聯(lián)

線(xiàn)程安全性概念

創(chuàng)新互聯(lián)公司于2013年開(kāi)始,先為嵐皋等服務(wù)建站,嵐皋等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢(xún)服務(wù)。為嵐皋企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。

當(dāng)對(duì)一個(gè)復(fù)雜對(duì)象進(jìn)行某種操作時(shí),從操作開(kāi)始到操作結(jié)束,被操作的對(duì)象往往會(huì)經(jīng)歷若干非法的中間狀態(tài)。調(diào)用一個(gè)函數(shù)(假設(shè)該函數(shù)是正確的)操作某對(duì)象常常會(huì)使該對(duì)象暫時(shí)陷入不可用的狀態(tài)(通常稱(chēng)為不穩(wěn)定狀態(tài)),等到操作完全結(jié)束,該對(duì)象才會(huì)重新回到完全可用的狀態(tài)。如果其他線(xiàn)程企圖訪(fǎng)問(wèn)一個(gè)處于不可用狀態(tài)的對(duì)象,該對(duì)象將不能正確響應(yīng)從而產(chǎn)生無(wú)法預(yù)料的結(jié)果,如何避免這種情況發(fā)生是線(xiàn)程安全性的核心問(wèn)題。

原子概念

當(dāng)方法調(diào)用似乎立即生效時(shí),該方法就是原子的。 因此,其他線(xiàn)程在方法調(diào)用之前或之后只能看到狀態(tài),而沒(méi)有中間狀態(tài)。 讓我們看一下非原子方法,看看原子方法如何使類(lèi)具有線(xiàn)程安全性。

public class UniqueIdNotAtomic {
   private volatile long counter = 0;
   public  long nextId() { 
     return counter++;  
   }  
}

類(lèi)UniqueIdNotAtomic通過(guò)使用易失性變量計(jì)數(shù)器創(chuàng)建唯一的ID。 我在第2行使用了volatile字段,以確保線(xiàn)程始終看到當(dāng)前值,如此處更詳細(xì)的說(shuō)明。 要查看此類(lèi)是否是線(xiàn)程安全的,我們使用以下測(cè)試:

public class TestUniqueIdNotAtomic {
   private final UniqueIdNotAtomic uniqueId = new UniqueIdNotAtomic();
   private long firstId;
   private long secondId;
   private void updateFirstId() {
     firstId  = uniqueId.nextId();
   }
   private void updateSecondId() {
     secondId = uniqueId.nextId();
   }
   @Test
   public void testUniqueId() throws InterruptedException {   
     try (AllInterleavings allInterleavings = 
         new AllInterleavings("TestUniqueIdNotAtomic");) {
     while(allInterleavings.hasNext()) { 
     Thread first = new Thread( () ->  { updateFirstId();  } ) ;
     Thread second = new Thread( () ->  { updateSecondId();  } ) ;
     first.start();
     second.start();
     first.join();
     second.join();  
     assertTrue(  firstId != secondId );
     }
     }
   }
}

為了測(cè)試計(jì)數(shù)器是否是線(xiàn)程安全的,我們需要在第16和17行中創(chuàng)建兩個(gè)線(xiàn)程。我們啟動(dòng)這兩個(gè)線(xiàn)程(第18和19行)。然后,我們等待直到兩個(gè)線(xiàn)程都通過(guò)第20和21行結(jié)束。 在兩個(gè)線(xiàn)程都停止之后,我們檢查兩個(gè)ID是否唯一,如第22行所示。

為了測(cè)試所有線(xiàn)程交織,我們使用來(lái)自vmlens第15行的AllInterleavings類(lèi),將完整的測(cè)試放在while循環(huán)中迭代所有線(xiàn)程交織。

運(yùn)行測(cè)試,我們看到以下錯(cuò)誤:

java.lang.AssertionError: 
   at org.junit.Assert.fail(Assert.java:91)
   at org.junit.Assert.assertTrue(Assert.java:43)

發(fā)生該錯(cuò)誤的原因是,由于操作++不是原子操作,因此兩個(gè)線(xiàn)程可以覆蓋另一個(gè)線(xiàn)程的結(jié)果。 我們可以在vmlens的報(bào)告中看到這一點(diǎn):

在發(fā)生錯(cuò)誤的情況下,兩個(gè)線(xiàn)程首先并行讀取變量計(jì)數(shù)器。 然后,兩個(gè)都創(chuàng)建相同的ID。 為了解決這個(gè)問(wèn)題,我們通過(guò)使用同步塊使方法原子化:

private final Object LOCK = new Object();
public  long nextId() {
  synchronized(LOCK) {
   return counter++;  
  } 
}

現(xiàn)在,該方法是原子的。 同步塊可確保其他線(xiàn)程無(wú)法看到該方法的中間狀態(tài)。

不訪(fǎng)問(wèn)共享狀態(tài)的方法是自動(dòng)原子的。 具有只讀狀態(tài)的類(lèi)也是如此。 因此,無(wú)狀態(tài)和不可變的類(lèi)是實(shí)現(xiàn)線(xiàn)程安全類(lèi)的簡(jiǎn)便方法。 他們所有的方法都是自動(dòng)的。

并非原子方法的所有用法都是自動(dòng)線(xiàn)程安全的。 將多個(gè)原子方法組合為相同的值通常會(huì)導(dǎo)致?tīng)?zhēng)用條件。 讓我們看看從ConcurrentHashMap獲取和放置的原子方法以了解原因。 當(dāng)以前的映射不存在時(shí),讓我們使用這些方法在映射中插入一個(gè)值:

public class TestUpdateTwoAtomicMethods {
   public void update(ConcurrentHashMap  map)  {
       Integer result = map.get(1);     
       if( result == null )  {
         map.put(1, 1);
       }
       else   {
         map.put(1, result + 1 );
       }  
   }
   @Test
   public void testUpdate() throws InterruptedException   {
     try (AllInterleavings allInterleavings = 
      new AllInterleavings("TestUpdateTwoAtomicMethods");) {
     while(allInterleavings.hasNext()) { 
     final ConcurrentHashMap  map = 
      new  ConcurrentHashMap(); 
     Thread first = new Thread( () ->  { update(map);  } ) ;
     Thread second = new Thread( () ->  { update(map);  } ) ;
     first.start();
     second.start();
     first.join();
     second.join();  
     assertEquals( 2 , map.get(1).intValue() );
     }
     }
   }  
}

該測(cè)試與先前的測(cè)試相似。 再次,我們使用兩個(gè)線(xiàn)程來(lái)測(cè)試我們的方法是否是線(xiàn)程安全的(第18行和第19行)。再次,我們?cè)趦蓚€(gè)線(xiàn)程完成之后測(cè)試結(jié)果是否正確(第24行)。運(yùn)行測(cè)試,我們看到以下錯(cuò)誤:

java.lang.AssertionError: expected:<2> but was:<1>
   at org.junit.Assert.fail(Assert.java:91)
   at org.junit.Assert.failNotEquals(Assert.java:645)

該錯(cuò)誤的原因是,兩種原子方法get和put的組合不是原子的。 因此,兩個(gè)線(xiàn)程可以覆蓋另一個(gè)線(xiàn)程的結(jié)果。 我們可以在vmlens的報(bào)告中看到這一點(diǎn):

在發(fā)生錯(cuò)誤的情況下,兩個(gè)線(xiàn)程首先并行獲取值。 然后,兩個(gè)都創(chuàng)建相同的值并將其放入地圖中。 要解決這種競(jìng)爭(zhēng)狀況,我們需要使用一種方法而不是兩種方法。 在我們的例子中,我們可以使用單個(gè)方法而不是兩個(gè)方法get和put來(lái)進(jìn)行計(jì)算:

public void update() {
  map.compute(1, (key, value) -> {
   if (value == null) {
     return 1;
   } 
   return value + 1;
  });
}

因?yàn)榉椒ㄓ?jì)算是原子的,所以這解決了競(jìng)爭(zhēng)條件。 雖然對(duì)ConcurrentHashMap的相同元素進(jìn)行的所有操作都是原子操作,但對(duì)整個(gè)地圖(如大?。┻M(jìn)行操作的操作都是靜態(tài)的。 因此,讓我們看看靜態(tài)意味著什么。

“靜止”是什么意思?

靜態(tài)意味著當(dāng)我們調(diào)用靜態(tài)方法時(shí),我們需要確保當(dāng)前沒(méi)有其他方法在運(yùn)行。 下面的示例顯示如何使用ConcurrentHashMap的靜態(tài)方法大?。?/p>

ConcurrentHashMap  map = 
   new  ConcurrentHashMap();
Thread first  = new Thread(() -> { map.put(1,1);});
Thread second = new Thread(() -> { map.put(2,2);});
first.start();
second.start();
first.join();
second.join();  
assertEquals( 2 ,  map.size());

通過(guò)等待直到所有線(xiàn)程都使用線(xiàn)程連接完成為止,當(dāng)我們調(diào)用方法大小時(shí),我們確保沒(méi)有其他線(xiàn)程正在訪(fǎng)問(wèn)ConcurrentHashMap。

方法大小使用在java.util.concurrent.atomic.LongAdder,LongAccumulator,DoubleAdder和DoubleAccumulator類(lèi)中也使用的一種機(jī)制來(lái)避免爭(zhēng)用。 與其使用單個(gè)變量存儲(chǔ)當(dāng)前大小,不如使用數(shù)組。 不同的線(xiàn)程更新數(shù)組的不同部分,從而避免爭(zhēng)用。 該算法在Striped64的Java文檔中有更詳細(xì)的說(shuō)明。

靜態(tài)類(lèi)和靜態(tài)方法對(duì)于收集競(jìng)爭(zhēng)激烈的統(tǒng)計(jì)數(shù)據(jù)很有用。 收集數(shù)據(jù)后,可以使用一個(gè)線(xiàn)程來(lái)評(píng)估收集的統(tǒng)計(jì)信息。

為什么在Java中沒(méi)有其他線(xiàn)程安全方法?

在理論計(jì)算機(jī)科學(xué)中,線(xiàn)程安全性意味著數(shù)據(jù)結(jié)構(gòu)滿(mǎn)足正確性標(biāo)準(zhǔn)。 最常用的正確性標(biāo)準(zhǔn)是可線(xiàn)性化的,這意味著數(shù)據(jù)結(jié)構(gòu)的方法是原子的。

對(duì)于常見(jiàn)的數(shù)據(jù)結(jié)構(gòu),存在可證明的線(xiàn)性化并發(fā)數(shù)據(jù)結(jié)構(gòu),請(qǐng)參見(jiàn)Maurice Herlihy和Nir Shavit撰寫(xiě)的《多處理器編程的藝術(shù)》一書(shū)。 但是要使數(shù)據(jù)結(jié)構(gòu)線(xiàn)性化,需要使用比較和交換之類(lèi)的昂貴同步機(jī)制,請(qǐng)參閱論文《定律:無(wú)法消除并發(fā)算法中的昂貴同步》以了解更多信息。

因此,研究了其他正確性標(biāo)準(zhǔn)(例如靜態(tài))。 因此,我認(rèn)為問(wèn)題不在于“為什么Java中沒(méi)有其他類(lèi)型的線(xiàn)程安全方法?” 但是,Java何時(shí)將提供其他類(lèi)型的線(xiàn)程安全性?
結(jié)論

Java中的線(xiàn)程安全性意味著類(lèi)的方法是原子的或靜態(tài)的。 當(dāng)方法調(diào)用似乎立即生效時(shí),該方法就是原子的。 靜態(tài)意味著當(dāng)我們調(diào)用靜態(tài)方法時(shí),我們需要確保當(dāng)前沒(méi)有其他方法在運(yùn)行。

目前,靜態(tài)方法僅用于收集統(tǒng)計(jì)信息,例如ConcurrentHashMap的大小。 對(duì)于所有其他用例,使用原子方法。 讓我們拭目以待,未來(lái)是否會(huì)帶來(lái)更多類(lèi)型的線(xiàn)程安全方法。

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線(xiàn),公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性?xún)r(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿(mǎn)足用戶(hù)豐富、多元化的應(yīng)用場(chǎng)景需求。


網(wǎng)頁(yè)標(biāo)題:Java中的線(xiàn)程安全性介紹-創(chuàng)新互聯(lián)
當(dāng)前鏈接:http://weahome.cn/article/hidjg.html

其他資訊

在線(xiàn)咨詢(xún)

微信咨詢(xún)

電話(huà)咨詢(xún)

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部