码迷,mamicode.com
首页 > 编程语言 > 详细

线程安全和非线程安全

时间:2017-11-18 23:43:43      阅读:224      评论:0      收藏:0      [点我收藏+]

标签:笔试   计数   线程   run   安全   stat   创建   await   hashmap   

Java面试和笔试中经常会问到

String线程安全StringBuffer线程安全StringBuilder非线程安全

HashMap非线程安全的HashTable线程安全的vector线程安全的

但是接下来会问你,不安全为什么还会用,因为HashMap效率更高,如果想让它变成安全的,加同步锁()

那什么叫线程安全什么叫非线程安全呢?

一、线程

什么叫做线程呢?

建议可以看一下阮一峰大神的博客:http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html

讲的非常通俗易懂,留言中的内容也要看,因为是转载的,有很多地方值得商榷。

二、线程安全和非线程安全

当多个线程同时操作同一个对象,修改某一个属性的时候,不会发生问题就称之为“线程安全”

可能会出现问题,就是“非线程安全的”

比如说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也是非线程安全的

三、如何取舍

当存在多个线程操作同一对象的时候,就采用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

输出结果

线程安全和非线程安全

标签:笔试   计数   线程   run   安全   stat   创建   await   hashmap   

原文地址:http://www.cnblogs.com/Darius-Bennett/p/7858063.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!