首页 > 其他分享 >parallelStream并发流线程安全问题

parallelStream并发流线程安全问题

时间:2022-11-08 08:55:25浏览次数:88  
标签:map 并发流 alist item 线程 result parallelStream

parallelStream并发流线程安全问题

起因

公司项目中用到定时任务进行数据获取任务,由于返回数据的类型是字符串,需要进行转换,变为我们定义的类型id,在准备我们定义的类型Map时,先找到所有类型数据,然后使用了**并行流**进行遍历,将name存储为key,id存储为value,生成转换map。测试阶段一切正常,但是当项目上线一段时间(某天夜里)后,突然出现定时任务中的报表部分执行失败。

出错位置:类型转换map在报错的那几次任务重中没有存储所有的类型键值对,简单来讲,就是丢了一些,导致没有找到转换类型的数据直接入了字符串到数据库,导致报表统计的update语句执行报错,报表数据丢失。

技术原因:parallelStream并行流并不是线程安全的,并发时存在数据丢失的情况,在往普通的collection中add数据时会出现抢占资源的线程问题。导致数据随机缺失

代码复现

public class TestParallelStream {
	public static void main(String[] args) {
		List<String> alist = new ArrayList<String>(Arrays.asList("1","2","3","4","5","6","7"));
		for(int i=0;i<10000;i++) {
			Map<String, String> result = new HashMap<String, String>();
			alist.parallelStream().forEach(item->{
				result.put(item, item);
			});
			System.out.println("i="+i+",map大小:"+result.size());
		}
	}
}

返回结果

......
i=5678,map大小:7
i=5679,map大小:7
i=5680,map大小:6      //出现map只有6个元素的情况了
i=5681,map大小:7
......

结论java8的并行流不保证线程安全,要保证线程安全需要加一个其他流程

解决

  1. 给collection上锁

    //对要存储元素的map要求线程安全
    Map<String, String> result = new HashMap<String, String>();
    修改为
    Map<String, String> result = Collections.synchronizedMap(new HashMap());
    			
    
  2. 使用标准for循环或增强for循环: 代码就不展示了

  3. 使用串行流stream

    alist.stream().forEach(item->{
    	result.put(item, item);
    });
    
  4. 使用java8中的收集器(使用parallelStream后使用collect )

alist.parallelStream().collect(Collectors.toList()).forEach(item->{
	result.put(item, item);
});

Collectors提供了toSet、toList、toConcurrentMap等方法

补充

https://www.cnblogs.com/weilx/p/16329743.html

标签:map,并发流,alist,item,线程,result,parallelStream
From: https://www.cnblogs.com/tlxf-blog/p/16868499.html

相关文章

  • 支持JDK19虚拟线程的web框架,之三:观察运行中的虚拟线程
    欢迎访问我的GitHub这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos《支持JDK19虚拟线程的web框架》系列文章链接支持JDK19虚拟线......
  • 守护线程例子
    packagecom.oop.state;/***测试守护线程*1、线程分为用户线程和守护线程*2、虚拟机必须确保用户线程执行完毕*3、虚拟机不用等待守护线程执行完毕*如:后......
  • Java 线程池之Jetty 线程池学习总结
    Java线程池之Jetty线程池学习总结前提Jetty11.0.x为什么是Jetty?Java提供4中创建线程池的快捷方式Executors.newFixedThreadPool();Executors.newCachedThreadPoo......
  • 线程池原理&源码分析&手写实现
    juc基础之线程池实现原理线程池概念线程池和数据库连接池非常类似,可以统一管理和维护线程,减少没必要的开销为什么使用使用线程池?因为频繁的开启线程或者停止线程,线程需......
  • java 多线程买票案例
    packagecom.tedu.threadStudy;publicclassstudyTicket{publicstaticvoidmain(String[]args){YouThreadyouThread=newYouThread();T......
  • 纯手写线程池+async注解实现异步任务
    spring整合多线程---@Async注解基本配置启动添加注解@SpringBootApplication@EnableAsyncpublic class Demo000Application {    public static void m......
  • java线程 Thread
    packagecom.tedu.threadStudy;publicclassstudyThread{publicstaticvoidmain(String[]args){MyThreadth1=newMyThread("线程1");My......
  • C#里的多线程,一网打尽thread,task,parallel
    C#里的多线程,一网打尽1.Syncawait2.Thread3.Threadpool4.Task5.Parallel Tasktask=newTask(()=>{});task.Start();Tasktask=Task.Run(()=>{};TaskFactoryta......
  • [2022.11.7]线程
    线程就是独立的执行路径;在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;main()称之为主线程,为系统的入口,用于执行整个程序;在一个进程中,如果开辟了多......
  • 创建两个分线程
    publicclassThreadTest{publicclassvoidmain(String[]args){3.//创建Thread类的子类的对象MyThreadm1=newMyThread1();MyT......