JAVA数据结构篇--13线程安全的Set 集合
前言:java 中用于存放不重复元素的set 集合,其中无序的HashSet,以及有序的LinkedHashSet和TreeSet 都是非线程安全的,那么多线程环境下,我们要存放不重复的元素,需要使用哪种集合进行数据存取;
1 使用:
Set set = Collections.synchronizedSet(new LinkedHashSet<>(10, 0.75f)); CopyOnWriteArraySet copyOnWriteArraySet = new CopyOnWriteArraySet<>(); Set 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 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 al; public CopyOnWriteArraySet() { al = new CopyOnWriteArrayList(); }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);}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 iterator() { return al.iterator();}// CopyOnWriteArrayList 下iteratorpublic Iterator iterator() { return new COWIterator(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 Set newSetFromMap(Map map) { return new SetFromMap<>(map);}private final Map m; // The backing mapprivate transient Set s; // Its keySetSetFromMap(Map 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 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://blog.csdn.net/l123lgx/article/details/128504721
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341