線程安全和非線程安全

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

輸出結果

相關文章
相關標籤/搜索