Java JUC怎么操作List安全类的集合
不安全的集合
在单线程应用中,通常采取new ArrayList(),指定一个List集合,用于存放可重复的数据。
但在多线程下,往往会出现意想不到的问题,代码如下所示:
import java.util.*; public class ListTest { public static void main(String[] args) throws InterruptedException { // 创建list集合 //List<String> lists = Arrays.asList("1", "2", "3"); // 不安全 List<String> lists = new ArrayList<>(); // 开启十个线程增加数据 for (int i = 1; i <= 40; i++) { new Thread(()->{ lists.add(UUID.randomUUID().toString().substring(0,5)); System.out.println(Thread.currentThread().getName()+"=="+lists); },String.valueOf(i)).start(); } } }
多线程操作同一集合对象信息,往往会出现java.util.ConcurrentModificationException异常报错信息。
Java中提供的安全措施
在java语言中,提供了一种新的List集合,java.util.Vector类,具体看下列代码:
import java.util.*; public class ListTest { public static void main(String[] args) throws InterruptedException { // 创建list集合 //List<String> lists = Arrays.asList("1", "2", "3"); // 不安全 //List<String> lists = new ArrayList<>(); List<String> lists = new Vector<>(); // 开启十个线程增加数据 for (int i = 1; i <= 40; i++) { new Thread(()->{ lists.add(UUID.randomUUID().toString().substring(0,5)); System.out.println(Thread.currentThread().getName()+"=="+lists); },String.valueOf(i)).start(); } } }
不会出现java.util.ConcurrentModificationException报错信息。
为什么能保证数据的安全操作?
采取了 synchronized 针对方法执行调用者加锁,保证add操作的多线程安全性!
JUC下的安全List集合
在JUC包下,提供有以下几种创建安全集合的方式。
方式一:Collections.synchronizedList(new ArrayList<>());
import java.util.*; public class ListTest { public static void main(String[] args) throws InterruptedException { List<String> lists = Collections.synchronizedList(new ArrayList<>()); // 开启十个线程增加数据 for (int i = 1; i <= 40; i++) { new Thread(()->{ lists.add(UUID.randomUUID().toString().substring(0,5)); System.out.println(Thread.currentThread().getName()+"=="+lists); },String.valueOf(i)).start(); } } }
查看底层源码实现逻辑
判断传入的 list 集合类型,判断类型是否为 java.util.RandomAccess,如果是则采取java.util.Collections.SynchronizedRandomAccessList构造集合,如果不是则采取java.util.Collections.SynchronizedList构造集合。
源码中对应的add操作逻辑如下所示:
采取synchronized同步代码块的方式,对数据的add操作实现加锁!
方式二:new CopyOnWriteArrayList();
import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; public class ListTest { public static void main(String[] args) throws InterruptedException { List<String> lists = new CopyOnWriteArrayList<>(); // 开启十个线程增加数据 for (int i = 1; i <= 40; i++) { new Thread(()->{ lists.add(UUID.randomUUID().toString().substring(0,5)); System.out.println(Thread.currentThread().getName()+"=="+lists); },String.valueOf(i)).start(); } } }
源码中的介绍如下:
显而易见,其逻辑如下所示:
调用add方法后,拿到java.util.concurrent.locks.ReentrantLock对象信息。
调用 lock.lock() 拿到锁!
将原数组对象copy操作,并创建原数组大小+1的新数组。
将新数据放入新数组中。
任何操作finally,都进行锁的释放!
性能方面
JUC包下的Lock操作,都比synchronized性能更好!
以上是Java JUC怎么操作List安全类的集合的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

Java 8引入了Stream API,提供了一种强大且表达力丰富的处理数据集合的方式。然而,使用Stream时,一个常见问题是:如何从forEach操作中中断或返回? 传统循环允许提前中断或返回,但Stream的forEach方法并不直接支持这种方式。本文将解释原因,并探讨在Stream处理系统中实现提前终止的替代方法。 延伸阅读: Java Stream API改进 理解Stream forEach forEach方法是一个终端操作,它对Stream中的每个元素执行一个操作。它的设计意图是处

胶囊是一种三维几何图形,由一个圆柱体和两端各一个半球体组成。胶囊的体积可以通过将圆柱体的体积和两端半球体的体积相加来计算。本教程将讨论如何使用不同的方法在Java中计算给定胶囊的体积。 胶囊体积公式 胶囊体积的公式如下: 胶囊体积 = 圆柱体体积 两个半球体体积 其中, r: 半球体的半径。 h: 圆柱体的高度(不包括半球体)。 例子 1 输入 半径 = 5 单位 高度 = 10 单位 输出 体积 = 1570.8 立方单位 解释 使用公式计算体积: 体积 = π × r2 × h (4

Java是热门编程语言,适合初学者和经验丰富的开发者学习。本教程从基础概念出发,逐步深入讲解高级主题。安装Java开发工具包后,可通过创建简单的“Hello,World!”程序实践编程。理解代码后,使用命令提示符编译并运行程序,控制台上将输出“Hello,World!”。学习Java开启了编程之旅,随着掌握程度加深,可创建更复杂的应用程序。
