一、ArrayList是线程不安全的,可以使用以下操作解决:

  1.使用相同功能的集合类替换,比如Vector集合是线程安全的,他们实现的接口都是一样的,但是Vector类是在jdk1.0出现的,不推荐使用

  

  2.使用 java.util.Collections类里面的静态方法synchronizedXXX(xxx),把不安全的集合当参数放进去。

  

  3.使用java.util.concurrent.CopyOnWriteArrayList或java.util.concurrent.CopyOnWriteArraySet

  

二、从上面第二个知道Map与Set都是线程不安全的,其中Map的第三个解决方法是 java.util.concurrent.ConcurrentHashMap

三、代码实现

  

package com.jenne.mydemo;

import org.junit.jupiter.api.Test;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet; public class TestCollection {
@Test
public void testList() {
/* //可能会出现java.util.ConcurrentModificationException
List<String> list = new ArrayList<>();
for (int i = 1; i <= 8; i++) {
new Thread(() -> {
list.add(Thread.currentThread().getName()+"--->测试");
System.out.println(list);
}).start();
}*/ /*List<String> list = new Vector<>();//不推荐
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
list.add(Thread.currentThread().getName()+"--->测试");
System.out.println(list);
}).start();
}*/ /*List<String> list = Collections.synchronizedList(new ArrayList<>());//不推荐
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
list.add(Thread.currentThread().getName()+"--->测试");
System.out.println(list);
}).start();
}*/ List<String> list = new CopyOnWriteArrayList<>();//推荐使用
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
list.add(Thread.currentThread().getName() + "--->测试");
System.out.println(list);
}).start();
}
} @Test
public void testSet() {
/*//java.util.ConcurrentModificationException
Set<String> set = new HashSet<>();
for (int i = 1; i <= 16; i++) {
new Thread(() -> {
set.add(Thread.currentThread().getName()+"--->测试");
System.out.println(set);
}).start();
}*/ /* Set<String> set = Collections.synchronizedSet(new HashSet<>());//不推荐
for (int i = 1; i <= 16; i++) {
new Thread(() -> {
set.add(Thread.currentThread().getName()+"--->测试");
System.out.println(set);
}).start();
}*/ Set<String> set = new CopyOnWriteArraySet<>();//推荐使用
for (int i = 1; i <= 16; i++) {
new Thread(() -> {
set.add(Thread.currentThread().getName() + "--->测试");
System.out.println(set);
}).start();
}
} @Test
public void testMap() {
/*//java.util.ConcurrentModificationException
Map<String,String> map = new HashMap<>();
for (int i = 1; i <= 16; i++) {
new Thread(() -> {
map.put(Thread.currentThread().getName(),"--->测试");
System.out.println(map);
}).start();
}*/ /*Map<String, String> map = Collections.synchronizedMap(new HashMap<>());//不推荐
for (int i = 1; i <= 16; i++) {
new Thread(() -> {
map.put(Thread.currentThread().getName(), "--->测试");
System.out.println(map);
}).start();
}*/ Map<String,String> map = new ConcurrentHashMap<>();//推荐使用
for (int i = 1; i <= 16; i++) {
new Thread(() -> {
map.put(Thread.currentThread().getName(),"--->测试");
System.out.println(map);
}).start();
} }
}

JUC---07解决集合线程不安全的更多相关文章

  1. 解决ArrayList线程不安全

    前些天做项目时,程序出现意外的问题,经后来分析是使用ArrayList这个线程不安全的方法导致 解决这个问题通常有两种方法(个人认为) 一:使用synchronized关键字,这个大家应该都很熟悉了, ...

  2. android 解决子线程进行UI操作

    Android确实不允许在子线程中进行UI操作的,但我们有时必须在子线程里去执行一些耗时的任务,然后根据任务的执行结果来更新相应的UI控件. Android提供了一套异步消息处理机制,可以解决子线程中 ...

  3. JUC源码分析-线程池篇(三)ScheduledThreadPoolExecutor

    JUC源码分析-线程池篇(三)ScheduledThreadPoolExecutor ScheduledThreadPoolExecutor 继承自 ThreadPoolExecutor.它主要用来在 ...

  4. JUC源码分析-线程池篇(二)FutureTask

    JUC源码分析-线程池篇(二)FutureTask JDK5 之后提供了 Callable 和 Future 接口,通过它们就可以在任务执行完毕之后得到任务的执行结果.本文从源代码角度分析下具体的实现 ...

  5. JUC源码分析-线程池篇(三)Timer

    JUC源码分析-线程池篇(三)Timer Timer 是 java.util 包提供的一个定时任务调度器,在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次. 1. Ti ...

  6. JUC源码分析-线程池篇(一):ThreadPoolExecutor

    JUC源码分析-线程池篇(一):ThreadPoolExecutor Java 中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序都可以使用线程池.在开发过程中,合理地使用线程池 ...

  7. Java 集合 线程安全

    Java中常用的集合框架中的实现类HashSet.TreeSet.ArrayList.ArrayDeque.LinkedList.HashMap.TreeMap都是线程不安全的,如果多个线程同时访问它 ...

  8. List 集合线程安全测试

    最近在做一些代码整理工作,涉及到List 线程安全问题,查了一些资料.网上有些资料说List 增减成员(Add , Remove) 是安全的,但不保证成员属性值访问安全性,及禁止对 List 跨线程遍 ...

  9. 线程间操作无效: 从不是创建控件“”的线程访问它~~~的解决方法~ 线程间操作无效: 从不是创建控件“Control Name'”的线程访问它问题的解决方案及原理分析

    看两个例子,一个是在一个进程里设置另外一个进程中控件的属性.另外一个是在一个进程里获取另外一个进程中控件的属性. 第一个例子 最近,在做一个使用线程控制下载文件的小程序(使用进度条控件显示下载进度)时 ...

随机推荐

  1. nginx+tomcat集群方法

    下载地址:wget http://nginx.org/download/nginx-1.16.1.tar.gz 解压:tar -zxvf 预编译 nginx+tomcat集群方法: 进入nginx配置 ...

  2. 原创-公司项目部署交付环境预检查shell脚本

    大型项目环境预检查脚本,根据自己实际情况修改脚本中变量,给大家一个思路~ #!/usr/bin/env bash root=$( cd $(dirname $0) pwd ) source " ...

  3. 破晓行动----带你总结JVM的知识大全(二)

    JVM运行时内存 + 垃圾回收与算法

  4. 从 ES6 高阶箭头函数理解函数柯里化

    前言:第一次看到多个连续箭头函数是在一个 react 项目中,然鹅确认了下眼神,并不是对的人,因为看得一脸懵逼.em......于是开始各种搜索,先是知道了多个连续箭头函数就是 es6 的多次柯里化的 ...

  5. Vue 组件的基础介绍

    1.组件定义 1.定义组件并引用 2.父组件向子组件传值 3.子组件向父组件传值 # 组件间传值:vuex (https://www.cnblogs.com/xiaonq/p/9697921.html ...

  6. 使用Redis做消息队列

    基于内存的单线程数据库,使Redis的线程安全性极高.而Redis的双向链表数据类型(List)天生就可作为消息队列存储消息. 在这里就不说消息队列的等等一些优点.但是补充一下Redis的List类型 ...

  7. Tensorflow学习笔记No.1

    使用tf.keras.Sequential()建立网络模型 整个过程可分为五步:1创建Sequential模型,2添加所需要的神经层,3使用.compile方法确定模型训练结构,4使用.fit方法 使 ...

  8. 【记】《.net之美》之读书笔记(二) C#中的泛型

    前言 上一篇读书笔记,很多小伙伴说这本书很不错,所以趁着国庆假期,继续我的读书之旅,来跟随书中作者一起温习并掌握第二章的内容吧. 一.理解泛型 1.为什么要使用泛型?-----通过使用泛型,可以极大地 ...

  9. git仓库之gitlab搭建使用

    一.简介 GitLab 是一个用于仓库管理系统的开源项目,使用git作为代码管理工具,并在此基础上搭建起来的web服务.类似github,常用在企业内部做git私有仓库使用: 二.gitlab安装 系 ...

  10. 拜托,别再问我怎么自学 Java 了!和盘托出

    假如有那么残酷的一天,我不小心喝错了一瓶药,一下子抹掉了我这十多年的编程经验,把我变成了一只小白.我想自学 Java,并且想要找到一份工作,我预计需要 6 个月的时间,前提条件是每天都处于高效率的学习 ...