搜尋
首頁Javajava教程Java中關於線程安全與非線程安全詳解

Java中關於線程安全與非線程安全詳解

Oct 12, 2017 am 10:09 AM
java關於安全

這篇文章主要介紹了Java線程安全與非線程安全解析,涉及非線程安全現像模擬以及線程安全的實現等相關內容,需要的朋友可以參考,一起交流學習。

ArrayList和Vector有什麼差別? HashMap和HashTable有什麼差別? StringBuilder和StringBuffer有什麼差別?這些都是Java面試中常見的基礎問題。面對這樣的問題,答案是:ArrayList是非線程安全的,Vector是線程安全的;HashMap是非線程安全的,HashTable是線程安全的;StringBuilder是非線程安全的,StringBuffer是線程安全的。因為這是昨晚剛背的《Java面試題大全》上面寫的。此時如果繼續問:什麼是線程安全?線程安全和非線程安全有什麼區別?分別在什麼情況下使用?這樣一連串的問題,一口老血就噴出來了…

非線程安全的現像模擬

這裡就使用ArrayList和Vector二者來說明。

下面的程式碼,在主線程中new了一個非線程安全的ArrayList,然後開1000個線程分別向這個ArrayList裡面添加元素,每個線程添加100個元素,等所有線程執行完成後,這個ArrayList的size應該是多少?應該是100000個?


public class Main 
{ 
  public static void main(String[] args) 
  { 
    // 进行10次测试 
    for(int i = 0; i < 10; i++) 
    { 
      test(); 
    } 
  } 
  public static void test() 
  { 
    // 用来测试的List 
    List<Object> list = new ArrayList<Object>(); 
    // 线程数量(1000) 
    int threadCount = 1000; 
    // 用来让主线程等待threadCount个子线程执行完毕 
    CountDownLatch countDownLatch = new CountDownLatch(threadCount); 
    // 启动threadCount个子线程 
    for(int i = 0; i < threadCount; i++) 
    { 
      Thread thread = new Thread(new MyThread(list, countDownLatch)); 
      thread.start(); 
    } 
    try 
    { 
      // 主线程等待所有子线程执行完成,再向下执行 
      countDownLatch.await(); 
    } 
    catch (InterruptedException e) 
    { 
      e.printStackTrace(); 
    } 
    // List的size 
    System.out.println(list.size()); 
  } 
} 
class MyThread implements Runnable 
{ 
  private List<Object> list; 
  private CountDownLatch countDownLatch; 
  public MyThread(List<Object> list, CountDownLatch countDownLatch) 
  { 
    this.list = list; 
    this.countDownLatch = countDownLatch; 
  } 
  public void run() 
  { 
    // 每个线程向List中添加100个元素 
    for(int i = 0; i < 100; i++) 
    { 
      list.add(new Object()); 
    } 
    // 完成一个子线程 
    countDownLatch.countDown(); 
  } 
}

上面進行了10次測試(為什麼要測試10次?因為非執行緒安全性並不是每次都會導致問題)。

輸出結果:


99946
100000
100000
100000
99998
99959
100000
99975
100000
99996

上面的輸出結果發現,並不是每次測試結果都是100000,有好幾次測試最後ArrayList的size小於100000,甚至時不時會拋出個IndexOutOfBoundsException異常。 (如果沒有這個現象可以多試幾次)

這就是非執行緒安全性帶來的問題了。上面的程式碼如果用於生產環境,就會有隱憂就會有BUG了。

再用執行緒安全的Vector來進行測試,上面程式碼改變一處,在test()方法中


##

List<Object> list = new ArrayList<Object>();

改變成



List<Object> list = new Vector<Object>();

再執行程式。


輸出結果:



100000
100000
100000
100000
100000
100000
100000
100000
100000
100000

再多跑幾次,發現都是100000,沒有任何問題。因為Vector是執行緒安全的,在多執行緒操作同一個Vector物件時,不會有任何問題。

再換成LinkedList試試,同樣還會出現ArrayList類似的問題,因為LinkedList也是非執行緒安全的。


二者如何取捨


非執行緒安全性是指多執行緒操作同一個物件可能會出現問題。而線程安全則是多線程操作同一個物件不會有問題。


執行緒安全必須要使用很多synchronized關鍵字來同步控制,所以必然會導致效能的降低。


所以在使用的時候,如果是多個執行緒操作同一個對象,那麼使用線程安全的Vector;否則,就使用效率更高的ArrayList。


非執行緒安全性!=不安全

#有人在使用過程中有一個不正確的觀點:我的程式是多線程的,不能使用ArrayList要使用Vector,這樣才安全。


非執行緒安全性並不是多執行緒環境下就不能使用。注意我上面有說到:多執行緒操作同一個物件。注意是同一個物件。例如最上面那個模擬,就是在主執行緒中new的一個ArrayList然後多個執行緒操作同一個ArrayList物件。


如果是每個線程中new一個ArrayList,而這個ArrayList只在這一線程中使用,那麼肯定是沒問題的。


線程安全的實作

#執行緒安全性是透過執行緒同步控制來實現的,也就是synchronized關鍵字。  


在這裡,我用程式碼分別實作了一個非執行緒安全的計數器和執行緒安全的計數器Counter,並對他們分別進行了多執行緒測試。


非線程安全的計數器:



public class Main 
{ 
  public static void main(String[] args) 
  { 
    // 进行10次测试 
    for(int i = 0; i < 10; i++) 
    { 
      test(); 
    } 
  } 
  public static void test() 
  { 
    // 计数器 
    Counter counter = new Counter(); 
    // 线程数量(1000) 
    int threadCount = 1000; 
    // 用来让主线程等待threadCount个子线程执行完毕 
    CountDownLatch countDownLatch = new CountDownLatch(threadCount); 
    // 启动threadCount个子线程 
    for(int i = 0; i < threadCount; i++) 
    { 
      Thread thread = new Thread(new MyThread(counter, countDownLatch)); 
      thread.start(); 
    } 
    try 
    { 
      // 主线程等待所有子线程执行完成,再向下执行 
      countDownLatch.await(); 
    } 
    catch (InterruptedException e) 
    { 
      e.printStackTrace(); 
    } 
    // 计数器的值 
    System.out.println(counter.getCount()); 
  } 
} 
class MyThread implements Runnable 
{ 
  private Counter counter; 
  private CountDownLatch countDownLatch; 
  public MyThread(Counter counter, CountDownLatch countDownLatch) 
  { 
    this.counter = counter; 
    this.countDownLatch = countDownLatch; 
  } 
  public void run() 
  { 
    // 每个线程向Counter中进行10000次累加 
    for(int i = 0; i < 10000; i++) 
    { 
      counter.addCount(); 
    } 
    // 完成一个子线程 
    countDownLatch.countDown(); 
  } 
} 
class Counter 
{ 
  private int count = 0; 
  public int getCount() 
  { 
    return count; 
  } 
  public void addCount() 
  { 
    count++; 
  } 
}

上面的測試程式碼中,開啟1000個線程,每個線程對計數器進行10000次累加,最終輸出結果應該是10000000。


但是上面程式碼中的Counter未進行同步控制,所以非執行緒安全性。


輸出結果:



9963727
9973178
9999577
9987650
9988734
9988665
9987820
9990847
9992305
9972233

稍微修改,把Counter改成執行緒安全的計數器:



class Counter 
{ 
  private int count = 0; 
  public int getCount() 
  { 
    return count; 
  } 
  public synchronized void addCount() 
  { 
    count++; 
  } 
}

上面只是在addCount()方法中加上了synchronized同步控制,就變成一個執行緒安全的計數器了。再執行程序。


輸出結果:



10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000

總結

以上是Java中關於線程安全與非線程安全詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
是否有任何威脅或增強Java平台獨立性的新興技術?是否有任何威脅或增強Java平台獨立性的新興技術?Apr 24, 2025 am 12:11 AM

新興技術對Java的平台獨立性既有威脅也有增強。 1)雲計算和容器化技術如Docker增強了Java的平台獨立性,但需要優化以適應不同雲環境。 2)WebAssembly通過GraalVM編譯Java代碼,擴展了其平台獨立性,但需與其他語言競爭性能。

JVM的實現是什麼,它們都提供了相同的平台獨立性?JVM的實現是什麼,它們都提供了相同的平台獨立性?Apr 24, 2025 am 12:10 AM

不同JVM實現都能提供平台獨立性,但表現略有不同。 1.OracleHotSpot和OpenJDKJVM在平台獨立性上表現相似,但OpenJDK可能需額外配置。 2.IBMJ9JVM在特定操作系統上表現優化。 3.GraalVM支持多語言,需額外配置。 4.AzulZingJVM需特定平台調整。

平台獨立性如何降低發展成本和時間?平台獨立性如何降低發展成本和時間?Apr 24, 2025 am 12:08 AM

平台獨立性通過在多種操作系統上運行同一套代碼,降低開發成本和縮短開發時間。具體表現為:1.減少開發時間,只需維護一套代碼;2.降低維護成本,統一測試流程;3.快速迭代和團隊協作,簡化部署過程。

Java的平台獨立性如何促進代碼重用?Java的平台獨立性如何促進代碼重用?Apr 24, 2025 am 12:05 AM

Java'splatformindependencefacilitatescodereusebyallowingbytecodetorunonanyplatformwithaJVM.1)Developerscanwritecodeonceforconsistentbehavioracrossplatforms.2)Maintenanceisreducedascodedoesn'tneedrewriting.3)Librariesandframeworkscanbesharedacrossproj

您如何在Java應用程序中對平台特定問題進行故障排除?您如何在Java應用程序中對平台特定問題進行故障排除?Apr 24, 2025 am 12:04 AM

要解決Java應用程序中的平台特定問題,可以採取以下步驟:1.使用Java的System類查看系統屬性以了解運行環境。 2.利用File類或java.nio.file包處理文件路徑。 3.根據操作系統條件加載本地庫。 4.使用VisualVM或JProfiler優化跨平台性能。 5.通過Docker容器化確保測試環境與生產環境一致。 6.利用GitHubActions在多個平台上進行自動化測試。這些方法有助於有效地解決Java應用程序中的平台特定問題。

JVM中的類加載程序子系統如何促進平台獨立性?JVM中的類加載程序子系統如何促進平台獨立性?Apr 23, 2025 am 12:14 AM

類加載器通過統一的類文件格式、動態加載、雙親委派模型和平台無關的字節碼,確保Java程序在不同平台上的一致性和兼容性,實現平台獨立性。

Java編譯器會產生特定於平台的代碼嗎?解釋。Java編譯器會產生特定於平台的代碼嗎?解釋。Apr 23, 2025 am 12:09 AM

Java編譯器生成的代碼是平台無關的,但最終執行的代碼是平台特定的。 1.Java源代碼編譯成平台無關的字節碼。 2.JVM將字節碼轉換為特定平台的機器碼,確保跨平台運行但性能可能不同。

JVM如何處理不同操作系統的多線程?JVM如何處理不同操作系統的多線程?Apr 23, 2025 am 12:07 AM

多線程在現代編程中重要,因為它能提高程序的響應性和資源利用率,並處理複雜的並發任務。 JVM通過線程映射、調度機制和同步鎖機制,在不同操作系統上確保多線程的一致性和高效性。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器