Java面試和筆試中常常會問到html
String線程安全StringBuffer線程安全StringBuilder非線程安全java
HashMap非線程安全的HashTable線程安全的vector線程安全的面試
可是接下來會問你,不安全爲何還會用,由於HashMap效率更高,若是想讓它變成安全的,加同步鎖()安全
那什麼叫線程安全什麼叫非線程安全呢?學習
1、線程測試
什麼叫作線程呢?ui
建議能夠看一下阮一峯大神的博客:http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.htmlthis
講的很是通俗易懂,留言中的內容也要看,由於是轉載的,有不少地方值得商榷。spa
2、線程安全和非線程安全線程
當多個線程同時操做同一個對象,修改某一個屬性的時候,不會發生問題就稱之爲「線程安全」
可能會出現問題,就是「非線程安全的」
好比說ArrayList和vector來講
在主線程中,new了一個ArrayList線程,如今開100個線程,每一個線程向arraylist中存放100個元素,最後ArrayList中有多少個對象,10000?
先建立一個線程類(另一篇文章會總結學習一下線程的三種實現方式)
1 class MyThread implements Runnable 2 { 3 private List<Object> list; 4 5 private CountDownLatch countDownLatch; 6 7 public MyThread(List<Object> list, CountDownLatch countDownLatch) 8 { 9 this.list = list; 10 this.countDownLatch = countDownLatch; 11 } 12 13 public void run() 14 { 15 // 每一個線程向List中添加100個元素 16 for(int i = 0; i < 100; i++) 17 { 18 list.add(new Object()); 19 } 20 21 // 完成一個子線程 22 countDownLatch.countDown(); 23 } 24 }
1 package threadTest; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import java.util.concurrent.CountDownLatch; 6 7 public class Test { 8 public static void test() 9 { 10 // 用來測試的List 11 List<Object> list = new ArrayList<Object>(); 12 13 // 線程數量(1000) 14 int threadCount = 1000; 15 16 // 用來讓主線程等待threadCount個子線程執行完畢 17 CountDownLatch countDownLatch = new CountDownLatch(threadCount); 18 19 // 啓動threadCount個子線程 20 for(int i = 0; i < threadCount; i++) 21 { 22 Thread thread = new Thread(new MyThread(list, countDownLatch)); 23 thread.start(); 24 } 25 26 try 27 { 28 // 主線程等待全部子線程執行完成,再向下執行 29 countDownLatch.await(); 30 } 31 catch (InterruptedException e) 32 { 33 e.printStackTrace(); 34 } 35 36 // List的size 37 System.out.println(list.size()); 38 } 39 public static void main(String[] args) 40 { 41 // 進行10次測試 42 for(int i = 0; i < 10; i++) 43 { 44 test(); 45 } 46 } 47 48 }
最後結果:
99799
99814
99765
100000
99868
99830
100000
99915
99858
99830
可是有時候會產生異常
這就是所謂的非線程安全
接下來換成線程安全的vector
將test裏邊的ArrayList換成vector
List<Object> list = new ArrayList<Object>();
List<Object> list = new Vector<Object>();
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
輸出結果
在多試幾回,仍是同樣的結果,由於vector是線程安全的,換成LinkedList結果和ArrayList相似,由於LinkedList也是非線程安全的
3、如何取捨
當存在多個線程操做同一對象的時候,就採用vector等線程安全的,若是不涉及,就採用ArrayList等,由於效率高
若是想要用ArrayList也能夠,線程安全必需要使用不少synchronized關鍵字來同步控制,加同步鎖
List<Object> list = Collections.synchronizedList(new ArrayList<Object>());
synchronized關鍵字同步,可是這樣會下降效率
另一種,實在方法前邊用synchronized修飾方法
一個計數器類
class Counter { private int count = 0; public int getCount() { return count; } public void addCount() { count++; } }
建立線程類
1 class MyThread implements Runnable 2 { 3 private Counter counter; 4 5 private CountDownLatch countDownLatch; 6 7 public MyThread(Counter counter, CountDownLatch countDownLatch) 8 { 9 this.counter = counter; 10 this.countDownLatch = countDownLatch; 11 } 12 13 public void run() 14 { 15 // 每一個線程向Counter中進行10000次累加 16 for(int i = 0; i < 10000; i++) 17 { 18 counter.addCount(); 19 } 20 21 // 完成一個子線程 22 countDownLatch.countDown(); 23 } 24 }
主線程
1 public class Main 2 { 3 public static void main(String[] args) 4 { 5 // 進行10次測試 6 for(int i = 0; i < 10; i++) 7 { 8 test(); 9 } 10 } 11 12 public static void test() 13 { 14 // 計數器 15 Counter counter = new Counter(); 16 17 // 線程數量(1000) 18 int threadCount = 1000; 19 20 // 用來讓主線程等待threadCount個子線程執行完畢 21 CountDownLatch countDownLatch = new CountDownLatch(threadCount); 22 23 // 啓動threadCount個子線程 24 for(int i = 0; i < threadCount; i++) 25 { 26 Thread thread = new Thread(new MyThread(counter, countDownLatch)); 27 thread.start(); 28 } 29 30 try 31 { 32 // 主線程等待全部子線程執行完成,再向下執行 33 countDownLatch.await(); 34 } 35 catch (InterruptedException e) 36 { 37 e.printStackTrace(); 38 } 39 40 // 計數器的值 41 System.out.println(counter.getCount()); 42 } 43 }
9760282
9999073
9999969
9990000
9998743
9965715
9990000
9994370
9990945
9993745
建立一個線程安全的計數器
class Counter { private int count = 0; public int getCount() { return count; } public synchronized void addCount() { count++; } }
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
輸出結果