ArrayList和Vector有什么区别?HashMap和HashTable有什么区别?StringBuilder和StringBuffer有什么区别?这些都是Java面试中常见的基础问题。面对这样的问题,回答是:ArrayList是非线程安全的,Vector是线程安全的;HashMap是非线程安全的,HashTable是线程安全的;StringBuilder是非线程安全的,StringBuffer是线程安全的。因为这是昨晚刚背的《Java面试题大全》上面写的。此时如果继续问:什么是线程安全?线程安全和非线程安全有什么区别?分别在什么情况下使用?这样一连串的问题,一口老血就喷出来了…非线程安全的现象模拟这里就使用ArrayList和Vector二者来说明。下面的代码,在主线程中new了一个非线程安全的ArrayList,然后开1000个线程分别向这个ArrayList里面添加元素,每个线程添加100个元素,等所有线程执行完成后,这个ArrayList的size应该是多少?应该是100000个?public class Main
{public static void main(String[] args){// 进行10次测试for(int i = 0; i < 10; i++){test();}}public static void test(){// 用来测试的ListList<Object> list = new ArrayList<Object>();// 线程数量(1000)int threadCount = 1000;// 用来让主线程等待threadCount个子线程执行完毕CountDownLatch countDownLatch = new CountDownLatch(threadCount);// 启动threadCount个子线程for(int i = 0; i < threadCount; i++){Thread thread = new Thread(new MyThread(list, countDownLatch));thread.start();}try{// 主线程等待所有子线程执行完成,再向下执行
            countDownLatch.await();}catch (InterruptedException e){e.printStackTrace();}// List的size
        System.out.println(list.size());}
}class MyThread implements Runnable
{private List<Object> list;private CountDownLatch countDownLatch;public MyThread(List<Object> list, CountDownLatch countDownLatch){this.list = list;this.countDownLatch = countDownLatch;}public void run(){// 每个线程向List中添加100个元素for(int i = 0; i < 100; i++){list.add(new Object());}// 完成一个子线程
        countDownLatch.countDown();}
}
上面进行了10次测试(为什么要测试10次?因为非线程安全并不是每次都会导致问题)。
输出结果:9994610000010000010000099998999591000009997510000099996上面的输出结果发现,并不是每次测试结果都是100000,有好几次测试最后ArrayList的size小于100000,甚至时不时会抛出个IndexOutOfBoundsException异常。(如果没有这个现象可以多试几次)
这就是非线程安全带来的问题了。上面的代码如果用于生产环境,就会有隐患就会有BUG了。再用线程安全的Vector来进行测试,上面代码改变一处,test()方法中
List<Object> list = new ArrayList<Object>();
改为
List<Object> list = new Vector<Object>();再运行程序。输出结果:100000100000100000100000100000100000100000100000100000100000再多跑几次,发现都是100000,没有任何问题。因为Vector是线程安全的,在多线程操作同一个Vector对象时,不会有任何问题。再换成LinkedList试试,同样还会出现ArrayList类似的问题,因为LinkedList也是非线程安全的。二者如何取舍非线程安全是指多线程操作同一个对象可能会出现问题。而线程安全则是多线程操作同一个对象不会有问题。线程安全必须要使用很多synchronized关键字来同步控制,所以必然会导致性能的降低。所以在使用的时候,如果是多个线程操作同一个对象,那么使用线程安全的Vector;否则,就使用效率更高的ArrayList。非线程安全!=不安全有人在使用过程中有一个不正确的观点:我的程序是多线程的,不能使用ArrayList要使用Vector,这样才安全。非线程安全并不是多线程环境下就不能使用。注意我上面有说到:多线程操作同一个对象。注意是同一个对象。比如最上面那个模拟,就是在主线程中new的一个ArrayList然后多个线程操作同一个ArrayList对象。如果是每个线程中new一个ArrayList,而这个ArrayList只在这一个线程中使用,那么肯定是没问题的。线程安全的实现线程安全是通过线程同步控制来实现的,也就是synchronized关键字。在这里,我用代码分别实现了一个非线程安全的计数器和线程安全的计数器Counter,并对他们分别进行了多线程测试。非线程安全的计数器:public class Main
{public static void main(String[] args){// 进行10次测试for(int i = 0; i < 10; i++){test();}}public static void test(){// 计数器Counter counter = new Counter();// 线程数量(1000)int threadCount = 1000;// 用来让主线程等待threadCount个子线程执行完毕CountDownLatch countDownLatch = new CountDownLatch(threadCount);// 启动threadCount个子线程for(int i = 0; i < threadCount; i++){Thread thread = new Thread(new MyThread(counter, countDownLatch));thread.start();}try{// 主线程等待所有子线程执行完成,再向下执行
            countDownLatch.await();}catch (InterruptedException e){e.printStackTrace();}// 计数器的值
        System.out.println(counter.getCount());}
}class MyThread implements Runnable
{private Counter counter;private CountDownLatch countDownLatch;public MyThread(Counter counter, CountDownLatch countDownLatch){this.counter = counter;this.countDownLatch = countDownLatch;}public void run(){// 每个线程向Counter中进行10000次累加for(int i = 0; i < 10000; i++){counter.addCount();}// 完成一个子线程
        countDownLatch.countDown();}
}class Counter
{private int count = 0;public int getCount(){return count;}public void addCount(){count++;}
}
上面的测试代码中,开启1000个线程,每个线程对计数器进行10000次累加,最终输出结果应该是10000000。但是上面代码中的Counter未进行同步控制,所以非线程安全。输出结果:9963727997317899995779987650998873499886659987820999084799923059972233稍加修改,把Counter改成线程安全的计数器:class Counter
{private int count = 0;public int getCount(){return count;}public synchronized void addCount(){count++;}
}
上面只是在addCount()方法中加上了synchronized同步控制,就成为一个线程安全的计数器了。再执行程序。输出结果:10000000100000001000000010000000100000001000000010000000100000001000000010000000

转载于:https://www.cnblogs.com/Free-Thinker/p/7015953.html

JAVA中的线程安全与非线程安全相关推荐

  1. JAVA中的线程安全与非线程安全,java面试题,java高级笔试题

    写在最前面,我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家.扫码加微信好友进[程序员面试学习交流群],免费领取.也欢迎各位一起在群里探讨技术. 转自 ...

  2. Java多线程:线程安全和非线程安全的集合对象

    转载自  Java多线程:线程安全和非线程安全的集合对象 一.概念: 线程安全:就是当多线程访问时,采用了加锁的机制:即当一个线程访问该类的某个数据时,会对这个数据进行保护,其他线程不能对其访问,直到 ...

  3. Java中主线程如何捕获子线程抛出的异常

    Java中主线程如何捕获子线程抛出的异常 参考文章: (1)Java中主线程如何捕获子线程抛出的异常 (2)https://www.cnblogs.com/jpfss/p/10272885.html ...

  4. PHP - 版本选择 - 线程安全与非线程安全 - 学习/实践

    1.应用场景 主要用于弄清楚为什么会有线程安全与非线程安全的不同语言版本,以及这种情况是不是一直存在, 是否有解决统一的办法吗- 2.学习/操作 1.文档阅读 PHP For Windows: Bin ...

  5. 浅谈 JAVA中静态初始化块和非静态初始化块的区别

    众所周知在JAVA编程语言中有两种初始化块: 静态初始化块 非静态初始化块 他们到底有什么区别呢?今天就浅谈一下JAVA中静态初始化块和非静态初始化块的区别 静态初始化块 定义: static{} 执 ...

  6. 【java的socket编程】结合多线程Thread实现通信(使用线程池和非线程池对比)、java开发UDP/IP网络程序

    结合多线程实现socket 使用非线程池(拓展Thread) 使用线程池(Executor pool) 使用DatagramPacket DatagramSocket开发UDP/IP程序 使用UDP获 ...

  7. Java中主线程如何捕获子线程抛出 ...

    这么来看待这个问题.首先明确线程代码的边界.其实很简单,Runnable接口的run方法所界定的边界就可以看作是线程代码的边界.Runnable接口中run方法原型如下:     <<   ...

  8. 《Java并发编程的艺术》——Java中的并发工具类、线程池、Execute框架(笔记)

    文章目录 八.Java中的并发工具类 8.1 等待多线程完成的CountDownLatch 8.2 同步屏障CyclicBarrier 8.2.1 CyclicBarrier简介 8.2.2 Cycl ...

  9. 【Java 多线程】Java中主线程如何捕获子线程抛出的异常

    首先明确线程代码的边界.其实很简单,Runnable接口的run方法所界定的边界就可以看作是线程代码的边界.Runnable接口中run方法原型如下: public void run(); 而所有的具 ...

最新文章

  1. 七十七、React中的propTypes,defaultProps和生命周期函数
  2. 算法代码_Python进化算法之多目标优化与代码实战
  3. 获取Java接口的所有实现类
  4. php 初始化漏洞,这样做是不是不会引起PHP全局变量未初始化漏洞
  5. 组件的v-model Mixin extends
  6. Java高级架构师需要掌握什么?
  7. oracle authentication_services,SQLNET.AUTHENTICATION_SERVICES= (NTS) 解释
  8. SQL Server的代码生成器
  9. CUDA中二级指针表示二级数组
  10. 190628每日一句
  11. 腾讯魔镜壁纸所在位置
  12. ckplayer.js视频播放插件
  13. FPS 每秒传输帧数(Frames Per Second)
  14. 软件测试工程师,不只是你眼中的点点点
  15. 解决IOS播放器KxMovie播放音频卡顿的问题
  16. ctf实验吧天网管理系统
  17. 五子棋游戏(JavaScript+JQuery+Canvas)
  18. H5常见问题 微信踩过得坑
  19. 使用在线UML制作工具Freedgo Design设计uml例子
  20. 因式分解结合最近邻:多层面的协同过滤模型

热门文章

  1. 自定义权限 android,Android权限控制之自定义权限
  2. Java RMI(2):项目中使用RMI
  3. java面试题十七 switch使用范围
  4. 大数据24小时:腾讯拟30亿元加码云计算,谷歌母公司Alphabet成立网络安全子公司“编年史”
  5. 基于redis分布式锁实现的多线程并发程序(原创)
  6. “薅羊毛”漏洞分析 | 我是如何到处“混吃混喝”的
  7. window实用快捷键
  8. elasticsearch-jdbc同步myslq数据到elasticsearch
  9. TensorFlow学习笔记(十)tf搭建神经网络可视化结果
  10. mysql的SQL_NO_CACHE(在查询时不使用缓存)和sql_cache用法