CopyOnWriteArraySet

article/2025/8/19 5:56:18

CopyOnWriteArraySet基于CopyOnWriteArrayList实现,其唯一的不同是在add时调用的是CopyOnWriteArrayList的addIfAbsent(若没有则增加)方法

CopyOnWriteArraySet介绍

它是线程安全的无序的集合,可以将它理解成线程安全的HashSet。有意思的是,CopyOnWriteArraySet和HashSet虽然都继承于共同的父类AbstractSet;但是,HashSet是通过“散列表(HashMap)”实现的,而CopyOnWriteArraySet则是通过“动态数组(CopyOnWriteArrayList)”实现的,并不是散列表。

和CopyOnWriteArrayList类似,CopyOnWriteArraySet具有以下特性:

1. 它最适合于具有以下特征的应用程序:Set 大小通常保持很小,只读操作远多于可变操作,需要在遍历期间防止线程间的冲突。

2. 它是线程安全的。

3. 因为通常需要复制整个基础数组,所以可变操作(add()、set() 和 remove() 等等)的开销很大。

4. 迭代器支持hasNext(), next()等不可变操作,但不支持可变 remove()等 操作。

5. 使用迭代器进行遍历的速度很快,并且不会与其他线程发生冲突。在构造迭代器时,迭代器依赖于不变的数组快照。

CopyOnWriteArraySet原理和数据结构

CopyOnWriteArraySet的数据结构,如下图所示:

说明:

  1. CopyOnWriteArraySet继承于AbstractSet,这就意味着它是一个集合。

  2. CopyOnWriteArraySet包含CopyOnWriteArrayList对象,它是通过CopyOnWriteArrayList实现的。而CopyOnWriteArrayList本质是个动态数组队列,

所以CopyOnWriteArraySet相当于通过通过动态数组实现的“集合”! CopyOnWriteArrayList中允许有重复的元素;但是,CopyOnWriteArraySet是一个集合,所以它不能有重复集合。因此,CopyOnWriteArrayList额外提供了addIfAbsent()和addAllAbsent()这两个添加元素的API,通过这些API来添加元素时,只有当元素不存在时才执行添加操作!

至于CopyOnWriteArraySet的“线程安全”机制,和CopyOnWriteArrayList一样,是通过volatile和互斥锁来实现的。这个在前一章节介绍CopyOnWriteArrayList时数据结构时,已经进行了说明,这里就不再重复叙述了。

CopyOnWriteArraySet函数列表

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

// 创建一个空 set。

CopyOnWriteArraySet()

// 创建一个包含指定 collection 所有元素的 set。

CopyOnWriteArraySet(Collection<? extends E> c)

// 如果指定元素并不存在于此 set 中,则添加它。

boolean add(E e)

// 如果此 set 中没有指定 collection 中的所有元素,则将它们都添加到此 set 中。

boolean addAll(Collection<? extends E> c)

// 移除此 set 中的所有元素。

void clear()

// 如果此 set 包含指定元素,则返回 true。

boolean contains(Object o)

// 如果此 set 包含指定 collection 的所有元素,则返回 true。

boolean containsAll(Collection<?> c)

// 比较指定对象与此 set 的相等性。

boolean equals(Object o)

// 如果此 set 不包含任何元素,则返回 true。

boolean isEmpty()

// 返回按照元素添加顺序在此 set 中包含的元素上进行迭代的迭代器。

Iterator<E> iterator()

// 如果指定元素存在于此 set 中,则将其移除。

boolean remove(Object o)

// 移除此 set 中包含在指定 collection 中的所有元素。

boolean removeAll(Collection<?> c)

// 仅保留此 set 中那些包含在指定 collection 中的元素。

boolean retainAll(Collection<?> c)

// 返回此 set 中的元素数目。

int size()

// 返回一个包含此 set 所有元素的数组。

Object[] toArray()

// 返回一个包含此 set 所有元素的数组;返回数组的运行时类型是指定数组的类型。

<T> T[] toArray(T[] a)

CopyOnWriteArraySet是通过CopyOnWriteArrayList实现的,它的API基本上都是通过调用CopyOnWriteArrayList的API来实现的。相信对CopyOnWriteArrayList了解的话,对CopyOnWriteArraySet的了解是水到渠成的事;所以,这里就不再对CopyOnWriteArraySet的代码进行详细的解析了。 

CopyOnWriteArraySet示例

下面,我们通过一个例子去对比HashSet和CopyOnWriteArraySet。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

import java.util.*;

import java.util.concurrent.*;

/*

 *  CopyOnWriteArraySet是“线程安全”的集合,而HashSet是非线程安全的。

 *

 *  下面是“多个线程同时操作并且遍历集合set”的示例

 *  (01) 当set是CopyOnWriteArraySet对象时,程序能正常运行。

 *  (02) 当set是HashSet对象时,程序会产生ConcurrentModificationException异常。

 *

 *

 */

public class CopyOnWriteArraySetTest1 {

  // TODO: set是HashSet对象时,程序会出错。

  //private static Set<String> set = new HashSet<String>();

  private static Set<String> set = new CopyOnWriteArraySet<String>();

  public static void main(String[] args) {

   

    // 同时启动两个线程对set进行操作!

    new MyThread("ta").start();

    new MyThread("tb").start();

  }

  private static void printAll() {

    String value = null;

    Iterator iter = set.iterator();

    while(iter.hasNext()) {

      value = (String)iter.next();

      System.out.print(value+", ");

    }

    System.out.println();

  }

  private static class MyThread extends Thread {

    MyThread(String name) {

      super(name);

    }

    @Override

    public void run() {

        int i = 0;

      while (i++ < 10) {

        // “线程名” + "-" + "序号"

        String val = Thread.currentThread().getName() + "-" + (i%6);

        set.add(val);

        // 通过“Iterator”遍历set。

        printAll();

      }

    }

  }

}

(某一次)运行结果:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

ta-1, tb-1, ta-1,

tb-1, ta-1,

tb-1, ta-1, ta-2,

tb-1, ta-1, ta-2, tb-1, tb-2,

ta-2, ta-1, tb-2, tb-1, ta-3,

ta-2, ta-1, tb-2, tb-1, ta-3, ta-2, tb-3,

tb-2, ta-1, ta-3, tb-1, tb-3, ta-2, ta-4,

tb-2, ta-1, ta-3, tb-1, tb-3, ta-2, ta-4, tb-2, tb-4,

ta-3, ta-1, tb-3, tb-1, ta-4, ta-2, tb-4, tb-2, ta-5,

ta-3, ta-1, tb-3, tb-1, ta-4, ta-2, tb-4, tb-2, ta-5, ta-3, tb-5,

tb-3, ta-1, ta-4, tb-1, tb-4, ta-2, ta-5, tb-2, tb-5, ta-3, ta-0,

tb-3, ta-1, ta-4, tb-1, tb-4, ta-2, ta-5, tb-2, tb-5, ta-3, ta-0, tb-3, tb-0,

ta-4, ta-1, tb-4, tb-1, ta-5, ta-2, tb-5, tb-2, ta-0, ta-3, tb-0,

tb-3, ta-1, ta-4, tb-1, tb-4, ta-2, ta-5, tb-5, ta-0, tb-0,

ta-1, tb-2, tb-1, ta-3, ta-2, tb-3, tb-2, ta-4, ta-3, tb-4, tb-3, ta-5, ta-4, tb-5, tb-4, ta-0, ta-5, tb-0,

tb-5, ta-1, ta-0, tb-1, tb-0,

ta-2, ta-1, tb-2, tb-1, ta-3, ta-2, tb-3, tb-2, ta-4, ta-3, tb-4, tb-3, ta-5, tb-5, ta-0, tb-0,

ta-4, ta-1, tb-4, tb-1, ta-5, ta-2, tb-5, tb-2, ta-0, ta-3, tb-0,

tb-3, ta-1, ta-4, tb-1, tb-4, ta-2, ta-5, tb-2, tb-5, ta-3, ta-0, tb-3, tb-0,

ta-4, tb-4, ta-5, tb-5, ta-0, tb-0,

结果说明:

由于set是集合对象,因此它不会包含重复的元素。

如果将源码中的set改成HashSet对象时,程序会产生ConcurrentModificationException异常。


http://chatgpt.dhexx.cn/article/32AhMTYP.shtml

相关文章

ArrayCopy方法[Java]

title: JavaArrayCopy方法 date: 2020-03-23 16:43:51 biog&#xff1a;https://www.huqifa.com/ tags: - Java categories: - Java ArrayCopy&#xff08;&#xff09; 作为小白一直在使用for循环对数组进行复制&#xff0c;添加和删除&#xff0c;学习过程中发现ArrayCopy&a…

数组—arraycopy()的用法

格式&#xff1a; arraycopy(要复制的数组,复制数组的起始位置,目标数组,复制的元素个数); 例子&#xff1a; int[] a {1,2,3,4,5,6};int[] b new int[4];//将数组a从第2个索引位置开始&#xff0c;截取4个元素到数组b从索引为0开始的位置添加。System.arraycopy(a, 2, b, …

System.arraycopy()方法详解

一、深度复制和浅度复制的区别 Java数组的复制操作可以分为深度复制和浅度复制&#xff0c;简单来说深度复制&#xff0c;可以将对象的值和对象的内容复制;浅复制是指对对象引用的复制。 二、System.arraycopy()方法实现复制 1、System中提供了一个native静态方法arraycopy(),…

Arraycopy方法

Arraycopy方法开发工具与关键技术&#xff1a;java 作者&#xff1a;彭浩达 撰写时间&#xff1a;2019年 5月 2日Arraycopy(Object src,int srcPos,Object dest,int destPos,int length) 描述&#xff1a;从指定源数组中复制一个数组&#xff0c;复制从指定的位置开始&#xff…

arraycopy方法简析

arraycopy&#xff08;System类的静态方法&#xff09; public static void arraycopy( Object src, int srcPos, Object dest, int destPos, int length) 简述 从指定源数组中复制一个数组&#xff0c;复制从指定的位置开始&#xff0c;到目标数组的指定位置结束。 参数&a…

arraycopy - 数组复制【详细图解】

1.arraycopy底层代码&#xff1a; 2.arraycopy的使用 第一个参数:源数组 第二个参数&#xff1a;在源数组中&#xff0c;被复制的数字开始复制的下标 第三个参数&#xff1a;目标数组 第四个参数&#xff1a;从目标数组中&#xff0c;从第几个下标开始放入复制的数据 第五…

关于Java中arraycopy的用法

一、实现数组之间的复制 int c[] {1,2,3,4,5},d[]; dnew int[5]; System.arraycopy(c, 0, d, 0, 5); //实现数组之间的复制 for(int n0;n<d.length;n) {System.out.println(d[n]); } 将c数组中从索引为0开始长度为5的数据复制到d中&#xff0c;并从索引为0开始。 输…

页面左侧二级菜单20种案例

向下滑动查看 本文由码农网 – 小峰原创&#xff0c;转载请看清文末的转载要求&#xff0c;欢迎参与我们的付费投稿计划&#xff01; jQuery作为一款主流的JavaScript前端开发框架&#xff0c;深受广告开发者的亲睐&#xff0c;同时jQuery有着不计其数的插件&#xff0c;特别是…

纯CSS实现二级菜单

书写基本样式 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-widt…

jQuery一级菜单和二级菜单

1、先做一级菜单&#xff0c;第一步设置body&#xff0c;把大概样子写出来。 2、第二步-1、用css设置通配符。 3、第二步-2、设置ul标签基础样式 。 4、第二步-3、设置类样式。 5、设置jquery内容的第一步先引入jQuery文件。 6、第二步设置一个函数在里面放入我们要设置成的效果…

bootstrap导航窗格响应式二级菜单

这次碰到的需求是响应式二级导航窗格&#xff0c;默认的导航窗格只有点击下拉框的二级窗格&#xff0c;会有如下问题&#xff1a;一级菜单无法添加超链接&#xff0c;二级菜单展示要多点一下。 实现目标&#xff1a; 1.滑动到指定区域&#xff0c;展示二级菜单。 2.一级菜单和…

html 悬停 二级菜单,使用HTML+CSS实现鼠标划过的二级菜单栏!

话不多说&#xff0c;先上效果图&#xff1a; 1、鼠标没在上面 image 2、鼠标放在一级菜单上&#xff0c;展开二级菜单 image 3、鼠标放在二级菜单上 image二级菜单测试 /*为了使菜单居中*/ body { padding-top:100px; text-align:center; } /* -------------菜单css代码------…

DIV+CSS 二级菜单实现

DIVCSS实现二级菜单 在网页制作中我们经常会用到的这样的导航栏二级菜单布局 实现效果如下&#xff1a; 设计思路就是通过 ul li 的双重嵌套来实现二级菜单&#xff0c;l利用display:none将二级菜单默认隐藏&#xff0c;li:hover鼠标悬浮时再将其显示出来。 需要注意的是&…

html 二级菜单 鼠标移动消失,鼠标一离开导航菜单,二级菜单就隐藏,移不到二级菜单...

鼠标一离开导航菜单,二级菜单就隐藏,移不到二级菜单 wky1682008 2015-12-28 09:27 html >无标题文档 ul{margin:0;padding:0;list-style:none; font-size:16px;font-family:"宋体";} a{ text-decoration:none;} ul{width:1000px; margin:50px auto 20px;backgro…

HTML一级菜单和二级菜单区别,一级菜单和二级菜单对不齐

html>二级菜单 *{margin: 0px; padding: 0px; } ul{font-size: 18px; color: white; list-style-type: none; text-align: center; width: 200px; line-height: 40px; background-color: black; position: relative; } a{color:white; text-decoration: none; } li{border-b…

HTML下拉框二级菜单

一、form表单 <div><form><div><!-- 下拉框 --><select>//默认项为第一个<option>广州</option><option>深圳</option><option>山东</option><option>北京</option></select></div>…

html 二级页面 教程,css 实现动态二级菜单

动态实现简单的二级菜单 当鼠标放到一级标签上时&#xff0c;鼠标会变成小手的形状 展示二级菜单&#xff0c;源码如下&#xff0c;复制即可直接使用Document * {margin: 0; padding: 0;} ul { list-style: none;} div { width: 100%; height: 50px; background-color: #ccc; }…

HTML+CSS制作二级菜单栏

今天我们来练习一下二级菜单栏,说实话比较简单,但是自己一个人写的时候错误百出,逻辑混乱,于是乎网上找了几个案例,借鉴了一下思路,才整明白,鄙人确实不才,哈哈! 效果图附上: 首先:我已链接了外部样式重置,所以无需自己亲自写: reset.css网上有很多,我用的是下面…

JS二级菜单

我们使用HTMLcssjs来写出二级菜单的简易效果 首先来看HTML的代码&#xff0c;这个没什么好说的 <div class"box"><div class"topbox"><ul><li class"bgc">春雨</li><li>夏风</li><li>秋雾<…

html 二级菜单

先放效果图&#xff1a; 首先设置菜单的基本轮廓 <div id"nav"><ul><li><a href"#">一级菜单1</a></li><li><a href"#">一级菜单2</a></li><li><a href"#" …