Java线程安全和非线程安全

Claude Code 处理长任务 + Cursor 专注交互:双栈协作的 3 种分工场景与响应提速 35% 实测 揭示 Claude Code 与 Cursor 在 AI 编程中的本质分工:Claude Code 作为离线式架构师处理跨文件、带约束的长链路重构(如单体拆微服务),Cursor 作为现场交互工程师专注秒级局部编辑;提出按任务切片动态切换的三种工程化协作场景,并给出结构化上下文构建、约束型 Prom 阅读详情

ArrayList和Vector有什么区别?HashMap和HashTable有什么区别?StringBuilder和StringBuffer有什么区别?这些都是Java面试中常见的基础问题。面对这样的问题,回答是:ArrayList是非线程安全的,Vector是线程安全的;HashMap是非线程安全的,HashTable是线程安全的;StringBuilder是非线程安全的,StringBuffer是线程安全的。因为这是昨晚刚背的《Java面试题大全》上面写的。此时如果继续问:什么是线程安全?线程安全和非线程安全有什么区别?分别在什么情况下使用?这样一连串的问题,一口老血就喷出来了…


非线程安全的现象模拟

这里就使用ArrayList和Vector二者来说明。

下面的代码,在主线程中new了一个非线程安全的ArrayList,然后开1000个线程分别向这个ArrayList里面添加元素,每个线程添加100个元素,等所有线程执行完成后,这个ArrayList的size应该是多少?应该是100000个?

[java]  view plain copy
  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.         // 用来测试的List  
  15.         List<Object> list = new ArrayList<Object>();  
  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(list, 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.         // List的size  
  41.         System.out.println(list.size());  
  42.     }  
  43. }  
  44.   
  45. class MyThread implements Runnable  
  46. {  
  47.     private List<Object> list;  
  48.       
  49.     private CountDownLatch countDownLatch;  
  50.       
  51.     public MyThread(List<Object> list, CountDownLatch countDownLatch)  
  52.     {  
  53.         this.list = list;  
  54.         this.countDownLatch = countDownLatch;  
  55.     }  
  56.       
  57.     public void run()  
  58.     {  
  59.         // 每个线程向List中添加100个元素  
  60.         for(int i = 0; i < 100; i++)  
  61.         {  
  62.             list.add(new Object());  
  63.         }  
  64.           
  65.         // 完成一个子线程  
  66.         countDownLatch.countDown();  
  67.     }  
  68. }  

上面进行了10次测试(为什么要测试10次?因为非线程安全并不是每次都会导致问题)。

输出结果:

99946

100000

100000

100000

99998

99959

100000

99975

100000

99996


上面的输出结果发现,并不是每次测试结果都是100000,有好几次测试最后ArrayList的size小于100000,甚至时不时会抛出个IndexOutOfBoundsException异常。(如果没有这个现象可以多试几次)

这就是非线程安全带来的问题了。上面的代码如果用于生产环境,就会有隐患就会有BUG了。


再用线程安全的Vector来进行测试,上面代码改变一处,test()方法中

[java]  view plain copy
  1. List<Object> list = new ArrayList<Object>();  
改成

[java]  view plain copy
  1. List<Object> list = new Vector<Object>();  

再运行程序。


输出结果:

100000

100000

100000

100000

100000

100000

100000

100000

100000

100000


再多跑几次,发现都是100000,没有任何问题。因为Vector是线程安全的,在多线程操作同一个Vector对象时,不会有任何问题。

再换成LinkedList试试,同样还会出现ArrayList类似的问题,因为LinkedList也是非线程安全的。


二者如何取舍

非线程安全是指多线程操作同一个对象可能会出现问题。而线程安全则是多线程操作同一个对象不会有问题。

线程安全必须要使用很多synchronized关键字来同步控制,所以必然会导致性能的降低。

所以在使用的时候,如果是多个线程操作同一个对象,那么使用线程安全的Vector;否则,就使用效率更高的ArrayList。


非线程安全!=不安全

有人在使用过程中有一个不正确的观点:我的程序是多线程的,不能使用ArrayList要使用Vector,这样才安全。

非线程安全并不是多线程环境下就不能使用。注意我上面有说到:多线程操作同一个对象。注意是同一个对象。比如最上面那个模拟,就是在主线程中new的一个ArrayList然后多个线程操作同一个ArrayList对象。

如果是每个线程中new一个ArrayList,而这个ArrayList只在这一个线程中使用,那么肯定是没问题的。


线程安全的实现

线程安全是通过线程同步控制来实现的,也就是synchronized关键字。   

在这里,我用代码分别实现了一个非线程安全的计数器和线程安全的计数器Counter,并对他们分别进行了多线程测试。


非线程安全的计数器:

[java]  view plain copy
  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. }  
  44.   
  45. class MyThread implements Runnable  
  46. {  
  47.     private Counter counter;  
  48.       
  49.     private CountDownLatch countDownLatch;  
  50.       
  51.     public MyThread(Counter counter, CountDownLatch countDownLatch)  
  52.     {  
  53.         this.counter = counter;  
  54.         this.countDownLatch = countDownLatch;  
  55.     }  
  56.       
  57.     public void run()  
  58.     {  
  59.         // 每个线程向Counter中进行10000次累加  
  60.         for(int i = 0; i < 10000; i++)  
  61.         {  
  62.             counter.addCount();  
  63.         }  
  64.           
  65.         // 完成一个子线程  
  66.         countDownLatch.countDown();  
  67.     }  
  68. }  
  69.   
  70. class Counter  
  71. {  
  72.     private int count = 0;  
  73.   
  74.     public int getCount()  
  75.     {  
  76.         return count;  
  77.     }  
  78.   
  79.     public void addCount()  
  80.     {  
  81.         count++;  
  82.     }  
  83. }  

上面的测试代码中,开启1000个线程,每个线程对计数器进行10000次累加,最终输出结果应该是10000000。

但是上面代码中的Counter未进行同步控制,所以非线程安全。

输出结果:

9963727

9973178

9999577

9987650

9988734

9988665

9987820

9990847

9992305

9972233


稍加修改,把Counter改成线程安全的计数器:

[java]  view plain copy
  1. class Counter  
  2. {  
  3.     private int count = 0;  
  4.   
  5.     public int getCount()  
  6.     {  
  7.         return count;  
  8.     }  
  9.   
  10.     public synchronized void addCount()  
  11.     {  
  12.         count++;  
  13.     }  
  14. }  

上面只是在addCount()方法中加上了synchronized同步控制,就成为一个线程安全的计数器了。再执行程序。

输出结果:

10000000

10000000

10000000

10000000

10000000

10000000

10000000

10000000

10000000

10000000

【AI产品与商业航图】Flux.1 完全开源 AI 绘图模型:本地部署与 ComfyUI 实战指南 Flux.1是一个开源项目,用户可以自由使用和修改,完全免除使用费用。🖥️本地部署支持:与一些依赖云端计算的工具不同,Flux.1支持本地部署,确保用户可以离线使用并自主控制数据隐私。🔄兼容ComfyUI框架:Flux.1可以无缝集成到ComfyUI中,用户可以享受更加简便和直观的操作界面。🎨卓越的图像生成能力:Flux.1能够生成高质量、细腻的图像,支持多种风格与创作主题的切换。💾低硬件要求。 阅读详情

相关推荐

MobilenetV1、V2、V3系列详解

Mobilenet系列模型作为当前主流的端侧轻量级模型被广泛应用,很多算法都会使用其作为backbone提取特征,这一章对Mobilenet系列模型V1,V2,V3做一个总结。

turned的博客 1万+

java中的线程安全

加了锁之后,有一个线程进到锁里面没有出来,导致锁资源没有得到释放,其他线程一直等待锁资源的释放,这样就导致了死锁的产生同步代码块和同步方法都是自动释放锁资源,所以不容易出现死锁;如果需要演示死锁案例;在同步锁中需要进行锁嵌套;注意:此处只是为了测试死锁,才进行的锁嵌套;以后使用时尽量避免锁嵌套(避免死锁)线程池:就是装线程的容器,预先在容器中创建指定个数的线程对象;当用户需要时,直接俄从容器中获取;用完了,再回收到线程池中(用完了放回去之前创建线程的方式:创建线程对象后,执行完毕则销毁线程对象;

qq_66013742的博客 3286

数据标注的下一代SOP,可能不是Word,而是一段Prompt

再给几个反例:“这个只是正常纹理,不算。真正用于数据生产的Prompt,可能至少包含:任务定义、正例、反例、边界案例、优先级、输出格式、验收逻辑。一个项目100个人,如果100个人对这句话有100种理解,最后返工的就不是一个框,而可能是几十万帧数据。一个项目启动以后,项目经理先研究SOP,培训组长,组长再培训标注员,最后几百个人按照同一套规则干活。实际上一个成熟的项目经理,最重要的能力之一,就是:把客户的业务语言翻译成生产规则。真正让项目难交付的,从来不是80%的普通数据,而是那20%的长尾数据。

AI数据标注猿 295

Java之线程安全

线程1获取到锁之后执行了对应的代码,线程2也要执行这个方法,但是检查锁的状态已经被持有,所以它处在堵塞(BLOCK)的状态,当线程1执行完方法之后,线程2才有可能获得到锁(并不一定),因为线程是抢占式执行的,可能线程1再次执行这个方法,再次先获得到了锁.现在举一个形象点的例子,小人1去上厕所,它获取到了锁,进入到上厕所,其他的小人要想上厕所,因为现在已经上了锁,所以他们只能处在等待堵塞的状态,当小人1出来之后,他们又在一起竞争(小人1也参与竞争),竞争到锁的就可以先上厕所,其它的小人又需要等待,

qq_64580912的博客 6225

creo二次开发使用映射

在creo进行二次开发时,一些无法直接通过访问底层代码来对特征进行操作,比如“镜像装配”,这个时候就可以使用映射(Mapkey)来完成一键镜像。 注:这是镜像装配的代码 ProError status; ProMacro macro; wstring Macro; strMacro = L"mapkey(continued) ~ Command ProCmdMirrorAssem ; mapkey(continued) ~ Activate mirror_component_dialog Sy

qq_49328512的博客 1607

Kalibr标定避坑指南:如何用AprilGrid板快速完成双目IMU标定

本文详细介绍了使用AprilGrid板进行Kalibr双目IMU联合标定的实战技巧,包括标定工具选型、数据采集优化、标定流程及结果验证。通过AprilGrid板的唯一标识性和抗遮挡优势,结合IMU静止标定和运动激励设计,显著提升标定精度。文章还提供了常见报错处理和高级优化技巧,帮助开发者高效完成传感器标定。

sunny的博客 282

Java线程安全

前段时间有测试一个后端对账单和话单采集服务,在测试过程中有涉及到数据库读写逻辑和并发的场景,所以结合经验针对系统技术架构设计了部分并发场景结合数据库读写时可能出现的一些问题的用例,也确实出现了一些测试环境容易忽视,线上环境确确实实可能出现的问题,当然最后还是得到了妥善的解决.下面说说后端测试应该考虑的一些线程安全和数据读写方面的问题. 前提:测试环境的架构尽量向线上环境的架构靠拢,比如线上如果采用分布式集群,测试环境如果是单机,那么部分问题自然无法暴露,如果测试环境无足够资源模拟线上的几十台集群环境,那么

qq_40132294的博客 2万+

ADAS系统架构与核心功能解析:从感知到执行的智能驾驶方案

高级驾驶员辅助系统(ADAS)是现代汽车智能化的核心技术,其本质是通过传感器融合、算法决策与车辆控制,构建一个“感知-决策-执行”的闭环系统。在技术原理上,ADAS依赖摄像头、毫米波雷达、激光雷达等多源传感器进行环境感知,并通过深度学习模型与融合算法(如卡尔曼滤波)构建精准的环境模型。其技术价值在于提供主动安全冗余与驾驶舒适性,核心应用场景包括自动紧急制动(AEB)、自适应巡航(ACC)及车道保持辅助(LKA)等。随着传感器成本下降与域控制器算力提升,ADAS正从高端配置向主流车型快速普及,并逐步向高阶导航

weixin_31062533的博客 414

Java 线程安全

Java 线程安全问题剖析及如何控制多线程环境下,并发编程的执行顺序。

weixin_63025863的博客 2020

systrace分析 之 问题初步定位

如下surfaceflinger空缺点,上面对应的bufferTX 中有buffer,但VSYNC-SF 过来后,SurfaceFlinger却没有去取,检查测试app “android.settings”, 也没有GPU completion 时间长的问题,所以该部分可以请SurfaceFlinger的owner 进一步确认为何不取buffer。. GPU拿的是acquireFence HWC拿的是releaseFence, GPU是绘图,HWC是合成显示,这两个是互相等待的关系,

yangzex的专栏 3194

国科大学习资料--数据挖掘(刘莹)--第三章习题及参考答案

国科大学习资料–数据挖掘(刘莹)–第三章习题及参考答案 国科大学习资料–数据挖掘(刘莹)–第三章习题及参考答案 国科大学习资料–数据挖掘(刘莹)–第三章习题及参考答案 第 3 章分类与回归 3.1简述决策树分类的主要步骤。 答:决策树生成的过程如下: (1)对数据源进行数据预处理, 得到训练集和测试集; (2)对训练集进行训练; (3)对初始决策树进行树剪枝; (4)由所得到的决策树提取分类规则; (5)使用测试数据集进行预测,评估决策树模型; 3.2给定决策树,选项有:(1)将决策树转换成规则,然后对结果

无名何许人的博客 3090

Java多线程之线程安全问题

Java多线程中的线程安全问题, 解决方法, 线程安全和不安全的标准类.

trong_ 的烂笔头 7224

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

java中线程安全和非线程安全_JAVA中的线程安全与非线程安全

就是线程同步的意思,就是当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的不能再对他进行操作了,必须等到这次访问结束以后才能对这个线程安全的方法进行访问什么叫线程安全:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。或者说:一个类或者程序所提供的接口对于线程来...

weixin_33721696的博客 343

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

java中线程安全和非线程安全_关于java线程安全和非线程安全的解释

今天学习spring AOP,介绍关于ThreadLocal协助spring为线程安全类。我困惑了许久。什么叫做线程非安全。就百度了一个很好的实例。下面是转载的,加上我自己的理解:ArrayList和Vector有什么区别?HashMap和HashTable有什么区别?StringBuilder和StringBuffer有什么区别?这些都是Java面试中常见的基础问题。面对这样的问题,回答是:Ar...

weixin_39725594的博客 190

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

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

一、概念: 线程安全:就是当多线程访问时,采用了加锁的机制;即当一个线程访问该类的某个数据时,会对这个数据进行保护,其他线程不能对其访问,直到该线程读取完之后,其他线程才可以使用。防止出现数据不一致或者数据被污染的情况。 线程不安全:就是不提供数据访问时的数据保护,多个线程能够同时操作某个数据,从而出现数据不一致或者数据污染的情况。 对于线程不安全的问题,一般会使用synchronized关键字加锁

大泡泡的专栏 2万+

java 线程安全和非线程安全

一、线程安全 所谓线程安全,就是指在多线程访问时数据时,采用加锁机制,当一个线程访问该类的某个数据时,就会进行保护,其他不相干的线程就不能够访问,除非该线程读取完毕,其他线程才可读取。这样就不会出现数据不一致或者数据污染。 线程安全保证了多线程同时操作同一个对象不会出现问题。 线程安全会使用很多synchronized关键字来进行同步控制,所以必然会导致性能大幅的降低。 二、非线程安全 线程不安全就是在运行中不提供数据访问保护,这样就可能出现多个线程先后更改数据,造成所得到的数据是脏数据。 非线

technologyleader的专栏 468

java中的线程安全和非线程安全

线程安全与非安全 线程安全是指,如果代码中有多个线程同时运行,如果每一次运行的结果都是一样,或者每一次运行的结果都是跟预期一样的,或者说跟单线程运行的结果一样。那么就是线程安全。 非线程安全是指多个线程同时运行的时候,出现不确定的结果。在运行的过程中可能产生脏数据。就是线程不安全。 线程安全产生的原因 其实就是两个或多个线程同时运行的时候,共享了某个数据。在多个线程同时操作该数据的情况下,该数据没...

m0_38037797的博客 267

java中线程安全和非线程安全_Java线程安全和非线程安全

ArrayList和Vector有什么区别?HashMap和HashTable有什么区别?StringBuilder和StringBuffer有什么区别?这些都是Java面试中常见的基础问题。面对这样的问题,回答是:ArrayList是非线程安全的,Vector是线程安全的;HashMap是非线程安全的,HashTable是线程安全的;StringBuilder是非线程安全的,StringBuff...

weixin_34365042的博客 110

Java 常用线程安全和非线程安全的集合

Java 的常用类集合介绍,从线程安全的角度去分析每个集合类的使用场景

weixin_36079865的博客 821
上一篇: MySQL查询优化的5个好用方法
下一篇: Mysql查询优化
OnePiece_Sky
博客等级 码龄15年 9粉丝 63原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值