JAVA数据结构篇--13线程安全的Set 集合

这篇具有很好参考价值的文章主要介绍了JAVA数据结构篇--13线程安全的Set 集合。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:java 中用于存放不重复元素的set 集合,其中无序的HashSet,以及有序的LinkedHashSet和TreeSet 都是非线程安全的,那么多线程环境下,我们要存放不重复的元素,需要使用哪种集合进行数据存取;

1 使用:

 Set<User> set = Collections.synchronizedSet(new LinkedHashSet<>(10, 0.75f));
 CopyOnWriteArraySet<User> copyOnWriteArraySet = new CopyOnWriteArraySet<>();
 Set<User> setFromMap = Collections.newSetFromMap(new ConcurrentHashMap<>());

 User userOne = new User();
 userOne.setId(1).setName("lisi").setAge(20);
 set.add(userOne);
 copyOnWriteArraySet.add(userOne);
 setFromMap.add(userOne);
 User userTwo = new User();
 userTwo.setId(2).setName("wangwu").setAge(20);
 set.add(userTwo);
 copyOnWriteArraySet.add(userTwo);
 setFromMap.add(userTwo);
 set.remove(userTwo);

 Iterator iterator1 = set.iterator();
 while (iterator1.hasNext()) {
     User user = (User) iterator1.next();
     System.out.println("user = " + user);
 }

2 过程:
2.1 放入获取元素:
Collections.synchronizedSet:通过使用synchronized 关键字修饰达到线程安全的目的

public Iterator<E> iterator() {
     return c.iterator(); // Must be manually synched by user!
 }

 public boolean add(E e) {
     synchronized (mutex) {return c.add(e);}
 }
 public boolean remove(Object o) {
     synchronized (mutex) {return c.remove(o);}
 }

CopyOnWriteArraySet<>():通过CopyOnWriteArrayList实现,也即底层数据结构使用的数组

private final CopyOnWriteArrayList<E> al;

 /**
  * Creates an empty set.
  */
 public CopyOnWriteArraySet() {
     al = new CopyOnWriteArrayList<E>();
 }
public boolean add(E e) {
	// 当元素不存在的时候添加元素
    return al.addIfAbsent(e);
}
publicboolean addIfAbsent(E e) {
   Object[] snapshot = getArray();
   return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
       addIfAbsent(e, snapshot);
}

/**
* A version of addIfAbsent using the strong hint that given
* recent snapshot does not contain e.
*/
private boolean addIfAbsent(E e, Object[] snapshot) {
   final ReentrantLock lock = this.lock;
   // 获取锁
   lock.lock();
   try {
       Object[] current = getArray();
       int len = current.length;
       if (snapshot != current) {// 当前的数组长度不等于传入进来的数组长度
           // Optimize for lost race to another addXXX operation
           // 从现有数组中判断要存入的e元素是否已经存在,存在直接返回false
           int common = Math.min(snapshot.length, len);
           for (int i = 0; i < common; i++)
               if (current[i] != snapshot[i] && eq(e, current[i]))
                   return false;
           if (indexOf(e, current, common, len) >= 0)
                   return false;
       }
       // 数组赋值
       Object[] newElements = Arrays.copyOf(current, len + 1);
       newElements[len] = e;
       setArray(newElements);
       return true;
   } finally {
   		//  释放锁
       lock.unlock();
   }
}
// 移除元素
public boolean remove(Object o) {
    Object[] snapshot = getArray();
    // 元素存在则进行移除否则直接返回
    int index = indexOf(o, snapshot, 0, snapshot.length);
    return (index < 0) ? false : remove(o, snapshot, index);
}
 private boolean remove(Object o, Object[] snapshot, int index) {
    final ReentrantLock lock = this.lock;
    lock.lock();// 获取锁
    try {
        Object[] current = getArray();
        int len = current.length;
        //  a: { break a; } 语法将a:之后的代码成为一个方法体,遇到 break跳出方法体
        if (snapshot != current) findIndex: {// 如果数组长度已经发生变化
            int prefix = Math.min(index, len);
            for (int i = 0; i < prefix; i++) {
                if (current[i] != snapshot[i] && eq(o, current[i])) {
                    index = i;
                    break findIndex;
                }
            }
            if (index >= len)
                return false;
            if (current[index] == o)
                break findIndex;
            index = indexOf(o, current, index, len);
            if (index < 0)
                return false;
        }
        // 数组长度-1
        Object[] newElements = new Object[len - 1];
        // 赋值剩下的元素到新的数组中
        System.arraycopy(current, 0, newElements, 0, index);
        System.arraycopy(current, index + 1,
                         newElements, index,
                         len - index - 1);
        setArray(newElements);
        return true;
    } finally {
        lock.unlock();
    }
}
// 元素遍历:
public Iterator<E> iterator() {
    return al.iterator();
}
// CopyOnWriteArrayList 下iterator
public Iterator<E> iterator() {
    return new COWIterator<E>(getArray(), 0);
}
private COWIterator(Object[] elements, int initialCursor) {
    cursor = initialCursor;
    snapshot = elements;
}
public boolean hasNext() {
    return cursor < snapshot.length;
}
public boolean hasPrevious() {
    return cursor > 0;
}
@SuppressWarnings("unchecked")
public E next() {
    if (! hasNext())
        throw new NoSuchElementException();
    return (E) snapshot[cursor++];
}

Collections.newSetFromMap(new ConcurrentHashMap<>()):使用ConcurrentHashMap实现元素的存取:

public static <E> Set<E> newSetFromMap(Map<E, Boolean> map) {
    return new SetFromMap<>(map);
}
private final Map<E, Boolean> m;  // The backing map
private transient Set<E> s;       // Its keySet

SetFromMap(Map<E, Boolean> map) {
    if (!map.isEmpty())
        throw new IllegalArgumentException("Map is non-empty");
    m = map;
    s = map.keySet();
}
public boolean remove(Object o)   { return m.remove(o) != null; }
public boolean add(E e) { return m.put(e, Boolean.TRUE) == null; }
public Iterator<E> iterator()     { return s.iterator(); }

3 总结:
3.1 Collections.synchronizedSet() 工具类通过对方法增加synchronized 关键字修饰达到线程安全的目的;CopyOnWriteArraySet 通过ReentrantLock 获取和释放锁达到线程安全的目的;Collections.newSetFromMap(new ConcurrentHashMap<>()) 借用ConcurrentHashMap 线程安全的Map集合达到线程安全的目的;
3.2 Collections.synchronizedSet() 工具类直接使用synchronized,并发情况下性能较差;CopyOnWriteArraySet 借助CopyOnWriteArrayList 使用ReentrantLock 性能好一些,但是底层使用了数组,占用内存较多;Collections.newSetFromMap(new ConcurrentHashMap<>()) 通过ConcurrentHashMap性能较好;文章来源地址https://www.toymoban.com/news/detail-575911.html

到了这里,关于JAVA数据结构篇--13线程安全的Set 集合的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python教程(12)——Python数据结构集合set介绍

    集合是一种无序、可变的数据结构,它也是一种变量类型,集合用于存储唯一的元素。集合中的元素不能重复,并且没有固定的顺序。在Python 提供了内置的 set 类型来表示集合,所以 set 就是集合的意思。 你可以使用大括号 {} 或者 set() 函数来创建一个集合。 需要注意

    2024年02月10日
    浏览(26)
  • Map,List,Set 等集合以及底层数据结构

    集合类存放于java.util包中。集合类存放的都是对象的引用,而非对象本身。常见的集合主要有三种——Set(集)、List(列表)和Map(映射)。其中,List和Set 都 实现 了 Collection 接口,并且List和Set也是接口,而 Map 为独立接口 。常见的实现类如下: List 的实现类有:ArrayList、

    2024年02月09日
    浏览(34)
  • 【数据结构与算法】C++的STL模板(迭代器iterator、容器vector、队列queue、集合set、映射map)以及算法例题

    更多算法例题链接: 【数据结构与算法】递推法和递归法解题(递归递推算法典型例题) 什么是迭代器(iterator) 迭代器(iterator)的定义: 迭代器是一种检查容器内元素并遍历元素的数据类型。 迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。 容器

    2024年04月14日
    浏览(36)
  • Java 数据结构集合

    详细请转到@pdai的博客 1.1 数组 (Array) 数组的优点: 存取速度快 数组的缺点: 事先必须知道数组的长度 插入删除元素很慢 空间通常是有限制的 需要大块连续的内存块 插入删除元素的效率很低 源码分析: 1、底层数据结构是Object 2、构造函数包括无参构造和有参数构造,有参构

    2024年01月24日
    浏览(27)
  • 探索Java集合框架—数据结构、ArrayList集合

    Java集合的使用相信大家都已经非常得心应手,但是我们怎么做到知其然,更知其所以然这种出神入化的境界呢?我们揭开集合框架底层神秘面纱来一探究竟 目录 一、背景介绍 二、思路方案 数据结构是什么? 数据结构可以分为线性和非线性两种数据结构 线性数据结构: 非

    2024年02月10日
    浏览(30)
  • springboot第49集:【思维导图】多线程,常用类与基础API,集合框架,泛型,数据结构源码...

    多线程创建方式一:继承Thread类 多线程创建方式二:实现Runnable接口 jdk5.0新增两种创建多线程的方式 image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png 优先级 image.png image.png image.png image.png image.png image.png 线程安全问题 image.p

    2024年01月21日
    浏览(34)
  • 【数据结构】 | java中 map和set 详解

    🎗️ 博客新人,希望大家一起加油进步 🎗️ 乾坤未定,你我皆黑马 我们首先来看一下集合的框架结构: Set实现了Collection接口,Map是一个单独存在的接口。 而下面又分别各有两个类,分别是TreeSet(HashSet)和 HashSet(HashMap) Map和Set的作用是用来查找和搜索的;以后涉及到

    2023年04月10日
    浏览(27)
  • java八股文面试[数据结构]——集合框架

    Java集合类主要由两个根接口Collection和Map派生出来的。 Collection派生出了三个子接口: Map接口派生: Map代表的是存储key-value对的集合,可根据元素的key来访问value。  因此Java集合大致也可分成 List、Set、Queue、Map四种接口体系 。 List代表了有序可重复集合,可直接根据元素的索

    2024年02月11日
    浏览(28)
  • 【数据结构一】初始Java集合框架(前置知识)

           Java语言在设计之初有一个非常重要的理念便是:write once,run anywhere!所以Java中的数据结构是已经被设计者封装好的了,我们只需要实例化出想使用的对象,便可以操作相应的数据结构了,本篇文章中我会向大家简单 介绍一下什么是数据结构 ,以及 对Java中常用的数

    2024年02月04日
    浏览(31)
  • Java02-迭代器,数据结构,List,Set ,Map,Collections工具类

    目录 什么是遍历? 一、Collection集合的遍历方式 1.迭代器遍历 方法 流程 案例 2. foreach(增强for循环)遍历 案例 3.Lamdba表达式遍历 案例 二、数据结构 数据结构介绍 常见数据结构 栈(Stack) 队列(Queue) 链表(Link) 散列表(Hash Table) 树(Tree) List接口 ArraysList集合 Linked

    2024年02月14日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包