java程序员多线程常见的代码bug 原创 2022-07-03 09:36:41.0 阅读(1657)次 **目录** [TOC] #### 前言 这篇文章主要用来记录我所收集的一些多线程环境下,java程序员常见的或者说容易忽视的、重要的、容易产生bug的代码样例,以此来加深自己对这些场景代码的印象,让我们一起少掉坑。文章会陆续更新,尽自己能力收集更多的样例。 #### CountDownLatch的错误使用 ```java CountDownLatch countDownLatch = new CountDownLatch(voGroupByBucketName.size()); for (......) { executorService.submit(() -> { try { xxxxxxx //countDownLatch.countDown(); } catch (Exception e) { ... } finally { countDownLatch.countDown(); } }); } countDownLatch.await(); ``` 上面的countDownLatch.countDown();经常有人不写到finally代码块中,造成executorService线程池报错后主线程意外假死,因为程序报错后countDownLatch.countDown()没有被执行,主线程一直await #### 使用Executors.newCachedThreadPool()创建线程来处理大量任务 ```java ExecutorService executorService = Executors.newCachedThreadPool(); ``` 由于newCachedThreadPool()创建线程池,如果有任务进入需要拿线程来处理任务,默认会从线程池的缓存中拿,如果没有就会创建新的线程,如果有大量任务需要被执行,那么newCachedThreadPool()的方式就会创建出大量的线程,造成java内存溢出或线程不够用了,所以建议最好还是用固定大小的线程池,这里也给出代码样例,如下: ```java ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("task-%d").build(); ExecutorService executorService = new ThreadPoolExecutor(20, 20,0, TimeUnit.SECONDS, new LinkedBlockingQueue(100),factory,new ThreadPoolExecutor.CallerRunsPolicy()); ``` ####线程池不设置队列大小或者设置很大的队列大小 ```java ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("task-%d").build(); ExecutorService executorService = new ThreadPoolExecutor(20, 20,0, TimeUnit.SECONDS, new LinkedBlockingQueue<>(),factory,new ThreadPoolExecutor.CallerRunsPolicy()); ``` 上面的new LinkedBlockingQueue<>()队列没有限制长度,在线程处理不过来的情况下会可能会堆积大量任务数据,造成内存溢出,我们应该设置合理的队列大小,正确的写法参考上一个问题的示例。 #### 使用Future来取线程池返回值时,Future.get()异常后取不到返回值问题 一直以为我都以为Future.get()跟Thread的run()方法一样会自己处理掉异常,然而并不是,这个问题还是很容易就犯错,如下代码:  图中122行代码get可能会报错,造成里面的List uploadPeopleStatus赋值不到,于是数据就丢失了,业务的要求应该是报错也要把里面的数据返回,于是要求我们正确的做法应该是线程里面要try catch异常并把数据返回。 #### 多线程共享变量之List.add()与clear()并发原子性问题 我们都知道CopyOnWriteArrayList是线程安全的List实现,所以在并发下执行add()方法是不会有并发问题的,但是如果在并发下又同时执行clear(),这时候就会出现并发问题了,因为这两者同时执行时并不是原子性的,需要我们代码加锁,举个例子,我看到的同事用disruptor来做并发处理业务,在他的EventHandler的方法中,有并发问题的代码如下: ```java protected List xxxList = new CopyOnWriteArrayList<>(BATCH_SIZE); @Override public void onEvent(EVENT event, long sequence, boolean endOfBatch) throws Exception { VALUE value = getValue(event); xxxList.add(value); if(xxxList.size() == BATCH_SIZE){ doBatchHandle(xxxList); xxxList.clear(); } if(endOfBatch && !xxxList.isEmpty()){ doBatchHandle(xxxList); xxxList.clear(); } } ``` 其中xxxList.add和xxxList.clear并发执行时就可能出问题了,正确的做法就是代码加锁,如下: ```java protected List xxxList = new CopyOnWriteArrayList<>(BATCH_SIZE); @Override public void onEvent(EVENT event, long sequence, boolean endOfBatch) throws Exception { VALUE value = getValue(event); synchronized (xxxList){ xxxList.add(value); if(xxxList.size() == BATCH_SIZE){ doBatchHandle(xxxList); xxxList.clear(); } if(endOfBatch && !xxxList.isEmpty()){ doBatchHandle(xxxList); xxxList.clear(); } } } ``` java java基础 上一篇:clickhouse删除数据时报错 下一篇:java阻塞的线程安全的优先级队列PriorityBlockingQueue
相关文章 java下载图片(976) java List间计算并集、差集、交集以及去重(3832) java使用BufferedImage放大或缩小图片(4643) java Md5工具类获取字符串的Md5值(1265) maven修改jar包版本不生效解决办法(7124) java stream List转Map与List转List与Map转List以及List转Map(8599) java父类转子类报错?怎么办?如何父类转子类(4508) 图片的base64字符转成BufferedImage(2665) java使用guava cache实现本地缓存(4854) java Map通过遍历器Iterator来实现遍历过程中删除元素来避免ConcurrentModificationException异常(1136) 推荐文章 使用spring4实现websocket连接(1) Parameter index out of range (1 > number of parameters, which is 0(7) spring cloud+feign+mybatis中使用seata0.9实现分布式事务(7) spring cloud gateway报错Only one connection receive subscriber allowed(82) spring cloud中Feign调用诡异报错MethodNotAllowed: status 405 reading(116) elasticsearch7.1保存时报错: Validation Failed: 1: type is missing;(7) 聊聊数据保存到MySQL后数据乱码的问题(1) jquery对象与dom对象互转(1) linux使用epel源yum安装iftop、nload、nginx等(2) linux下nginx安装其他模块(1) 热门文章 java stream去重的几种方式(40819) the dependencies of some of the beans in the application context form a cycle(16324) 解决mybatis打印查询结果集造成太多日志的问题(9839) java enum枚举转list和Map(9722) java stream List转Map与List转List与Map转List以及List转Map(8468) ServletRequest转HttpServletRequest设置header之后取不到header的问题(8434) java中BufferedImage转成 base64字符串(8098) 切分List集合为多个List集合(7385) maven修改jar包版本不生效解决办法(6990) bootstrap.yml配置报错:Could not resolve placeholder 'xx' in value (6949) 标签列表 java java java java java java java基础 微服务 异常处理 mysql clickhouse clickhouse clickhouse clickhouse clickhouse spring cloud spring boot linux elasticsearch feign jdbc spring js docker postgresql solr seata nginx maven gateway hsqldb 数据库 架构 大数据分析 分布式事务 redis canal dubbo hadoop 消息队列 win10 websocket springmvc git html select2 mybatis jenkins rocketmq quartz activemq 数据库集群 ajax bat 电脑 笔记 eclipse 设计模式 阿里云 github freemarker jvm jquery javamail redission redission对象 hystrix http hibernate springmail svn ubuntu ueditor xheditor zookeeper 分布式 小程序 开发工具 gitlab