线程安全和非线程安全

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

输出结果