您的位置:首页 > 运维架构

JUC集合---CopyOnWriteArraySet

2017-08-29 17:53 399 查看
内容包括:

CopyOnWriteArraySet介绍

CopyOnWriteArraySet原理和数据结构

CopyOnWriteArraySet函数列表

CopyOnWriteArraySet源码(JDK1.7.0_40版本)

CopyOnWriteArraySet示例

CopyOnWriteArraySet产生

public class HashSetTest {

public static void main(String[] args) {

final Set set = Collections.synchronizedSet(

new HashSet());

//开启A线程向set中放数据

new Thread(new Runnable() {

@Override

public void run() {

int i;

while (true) {

try {

i = new Random().nextInt(1000);

System.out.println(“准备加入到Set…”);

set.add(i);

System.out.println(“加入到Set:” + i);

} catch (Exception e) {

e.printStackTrace();

break;

}

}

System.exit(0);

}

}, “A”).start();

//开启B线程删除set中的数据

new Thread(new Runnable() {

@Override

public void run() {

Iterator iter = null;

while (true) {

synchronized (set) {

try {

iter = set.iterator();

System.out.println(“开始迭代..”);

int i;

while (iter.hasNext()) {

System.out.println(“准备删除Set….”);

i = iter.next();

iter.remove();

System.out.println(“删除Set:” + i);

}

} catch (Exception e) {

e.printStackTrace();

break;

}

}

}

System.exit(0);

}

}, “B”).start();

}

}

以上代码运行时会产生ConcurrentModificationException(并发修改)异常

CopyOnWriteArraySet介绍

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

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

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

2. 它是线程安全的。

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

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

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

CopyOnWriteArraySet原理和数据结构



说明:

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

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

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

至于CopyOnWriteArraySet的“线程安全”机制,和CopyOnWriteArrayList一样,是通过volatile和互斥锁来实现的。

CopyOnWriteArraySet函数列表

方法函数详细源码

// 创建一个空 set。

copyonwritearrayset()

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

copyonwritearrayset(collection

CopyOnWriteArraySet函数源码

CopyOnWriteArraySet是通过CopyOnWriteArrayList实现的,它的API基本上都是通过调用CopyOnWriteArrayList的API来实现的。

CopyOnWriteArraySet示例

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

import java.util.*;

import java.util.concurrent.*;

/*

* copyonwritearrayset是“线程安全”的集合,而hashset是非线程安全的。

*

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

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

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

*

* @author skywang

*/

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


}

(某一次)运行结果:

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异常。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: