正确理解线程安全与非线程安全

引言

有没有常被人问到以下几个问题:
  1. ArrayList和Vector有什么区别?
  2. HashMap和HashTable有什么区别?
  3. StringBuilder和StringBuffer有什么区别?
每当听到这样的问题时,答案则无非是来自‘XX面试宝典’的那几句:
  1. ArrayList是非线程安全的,Vector是线程安全的
  2. HashMap是非线程安全的,HashTable是线程安全的
  3. StringBuilder是非线程安全的,StringBuffer是线程安全的
突然发现我们平时用的基本都是非线程安全的,甚至线程安全的有人从来没用过。那么我们是否写的程序都存在安全问题,下面我们将就安全进行一个解释。

安全问题的暴露

在高并发的场景下,我们会利用java的多线程特性提高效率。当多个线程共享一个资源的时候,则会出现是否安全的问题。例如以下代码关于ArrayList的使用场景,我们假设有这么一个线程
  package cn.buglife.learn.thread;

  import java.util.List;
  import java.util.UUID;
  import java.util.concurrent.CountDownLatch;

  /**
   * 定义一个线程(往给定的列表添加100个数据)
   * <p>
   * Created by zhangjun on 16/6/23.
   */
  public class LearnThread implements Runnable {

      private List<String> resource;

      private CountDownLatch countDownLatch;

      public LearnThread(List<String> resource, CountDownLatch countDownLatch) {
          this.resource = resource;
          this.countDownLatch = countDownLatch;
      }

      @Override
      public void run() {
          for (int i = 0; i < 100; i++) {
              resource.add(UUID.randomUUID().toString());
          }

          countDownLatch.countDown();
      }
  }
接下来我们启动100个线程去帮助我们完成资源的录入,理论期望应该资源数组大小为10000
  package cn.buglife.learn.thread;

  import java.util.ArrayList;
  import java.util.List;
  import java.util.concurrent.CountDownLatch;

  /**
   * Created by zhangjun on 16/6/23.
   */
  public class ThreadSafe {

      public static void main(String[] args) {
          List<String> unSafeList = new ArrayList<String>();
          //启动100个线程
          int threadCount = 100;
          CountDownLatch countDownLatch = new CountDownLatch(threadCount);

          for (int i=0; i<threadCount;i++){
              Thread thread = new Thread(new LearnThread(unSafeList,countDownLatch));
              thread.start();
          }

          try {
              countDownLatch.await();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }

          System.out.print(unSafeList.size());
      }
  }
执行上述程序5次得到的结果如下
资源大小耗时
9999119
10000115
9999119
9999114
9999117
若使用线程安全的Vector呢?
package cn.buglife.learn.thread;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.CountDownLatch;

/**
 * Created by zhangjun on 16/6/23.
 */
public class ThreadSafe {

    public static void main(String[] args) {
        Long time = new Date().getTime();
        List<String> safeList = new Vector<String>();
        //启动100个线程
        int threadCount = 100;
        CountDownLatch countDownLatch = new CountDownLatch(threadCount);

        for (int i=0; i<threadCount;i++){
            Thread thread = new Thread(new LearnThread(safeList,countDownLatch));
            thread.start();
        }

        //主线程等待其他线程全部执行完再执行
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("资源大小:"+safeList.size());
        System.out.print("耗时:"+(new Date().getTime()-time));

    }

}
上述代码执行结果:
资源大小耗时
10000112
10000118
10000105
10000123
10000125

如何选择

根据以上现象可以看出,非线程安全的ArrayList结构会在多线程使用的过程中随机性得使计算错乱,那么是不是非线程安全得数据结构就不要用了呢?
非线程安全是指多线程操作同一个对象可能会出现一些误差问题。而 线程安全则是指多线程操作同一个对象不会出现问题。 那么又有一个新得问题,是不是非线程安全得是不是就不能在多线程环境下使用了?答案是No,我们需要明确得是:
  1. 线程安全问题是针对多线程环境下,多个线程操作同一个对象
  2. 鱼和熊掌不可兼得,线程安全得代价就是性能相对得有所下降
  3. 非线程安全得对象在独立线程内是不存在问题得

结论

线程安全与非线程安全取决于应用得环境,是取是舍需要根据所处环境决定,切勿盲目下结论。

转载于:https://my.oschina.net/crazyharry/blog/1105141

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值