温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java JUC中如何操作List安全类的集合

发布时间:2021-07-02 09:46:38 来源:亿速云 阅读:182 作者:小新 栏目:开发技术

小编给大家分享一下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 JUC中如何操作List安全类的集合

多线程操作同一集合对象信息,往往会出现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 JUC中如何操作List安全类的集合

不会出现java.util.ConcurrentModificationException报错信息。

为什么能保证数据的安全操作?

Java JUC中如何操作List安全类的集合

采取了 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();
        }
    }
}

查看底层源码实现逻辑

Java JUC中如何操作List安全类的集合

判断传入的 list 集合类型,判断类型是否为 java.util.RandomAccess,如果是则采取java.util.Collections.SynchronizedRandomAccessList构造集合,如果不是则采取java.util.Collections.SynchronizedList构造集合。

源码中对应的add操作逻辑如下所示:

Java JUC中如何操作List安全类的集合

采取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();
        }
    }
}

源码中的介绍如下:

Java JUC中如何操作List安全类的集合

Java JUC中如何操作List安全类的集合

显而易见,其逻辑如下所示:

  1. 调用add方法后,拿到java.util.concurrent.locks.ReentrantLock对象信息。

  2. 调用 lock.lock() 拿到锁!

  3. 将原数组对象copy操作,并创建原数组大小+1的新数组。

  4. 将新数据放入新数组中。

  5. 任何操作finally,都进行锁的释放!

性能方面

JUC包下的Lock操作,都比synchronized性能更好!

看完了这篇文章,相信你对“Java JUC中如何操作List安全类的集合”有了一定的了解,如果想了解更多相关知识,欢迎关注亿速云行业资讯频道,感谢各位的阅读!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI