简介

本文是主要介绍,并发容器CopyOnWriteArrayList和CopyOnWriteArraySet(不含重复元素的并发容器)的基本原理和使用示例。

欢迎探讨,如有错误敬请指正

如需转载,请注明出处 http://www.cnblogs.com/nullzx/


1. CopyOnWriteArrayList

从类的名字我们可以看出,该类是基于ArrayList类实现的。而CopyOnWrite的意思显然借鉴了操作系统中写时拷贝的思想。该容器主要有以下特点:

1)读取该容器中元素时,不加锁。

2)写操作,会加锁,也就是说多个线程进行写入操作时会逐个获取锁后进行写入。

3)写操作不会影响读操作,也就是说线程要进行读操作时,不会因为有线程正在进行写操作而阻塞。

下面是写操作源代码

    public E set(int index, E element) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
E oldValue = get(elements, index); if (oldValue != element) {
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len);
newElements[index] = element;
setArray(newElements);
} else {
// Not quite a no-op; ensures volatile write semantics
setArray(elements);
}
return oldValue;
} finally {
lock.unlock();
}
}

工作原理:在CopyOnWriteArrayList类中,定一了一个数组private transient volatile Object[] array;容器中存储的对象的索引都会放在这个数组中。

写操作首先会获取锁。当获取锁成功后,复制该数组到一个新的数组newElements中,然后修改或者添加某个元素(注意这个时候如果有线程来读取该数组中的某个值,由于读操作不需要获取锁,所以不会被阻塞,但是可能不能读取到最新修改后的值)。修改后,让array指向经过修改后的新数组newElements,原array指向的数组会被垃圾回收器回收。

下面的代码是CopyOnWriteArrayList的演示例程

package javalearning;

import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /*CopyOnWriteArrayList演示例程*/
public class CopyOnWriteArrayListDemo {
/*定义一个CopyOnWriteArrayList对象,读线程和写线程会同时使用它*/
private CopyOnWriteArrayList<Integer> cowal = new CopyOnWriteArrayList<Integer>();
{
/*对CopyOnWriteArrayList对象初始化*/
cowal.add(1);
cowal.add(2);
cowal.add(3);
} private Random rnd = new Random(); public class ReadThread implements Runnable{
private String id; public ReadThread(String id){
this.id = id;
} @Override
public void run() {
try {
Thread.sleep(rnd.nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
/*读线程会打印出CopyOnWriteArrayList对象的所有数值*/
System.out.println(id + " " + cowal.toString());
} } public class WriteThread implements Runnable{ /*写线程会将CopyOnWriteArrayList对象的所有数值加1*/
@Override
public void run() {
for(int i = 0; i < cowal.size(); i++){
int x = cowal.get(i); /*每修改一个元素之前加锁*/
cowal.set(i, x+1);
/*修改完一个元素后释放锁*/ try{
Thread.sleep(rnd.nextInt(1000));
}catch(InterruptedException e){
e.printStackTrace();
}
}
} } public static void main(String[] args){
ExecutorService es = Executors.newCachedThreadPool();
CopyOnWriteArrayListDemo demo = new CopyOnWriteArrayListDemo();
/*创建两个读线程*/
es.execute(demo.new ReadThread("r1"));
es.execute(demo.new ReadThread("r2"));
/*创建两个写线程*/
es.execute(demo.new WriteThread());
es.execute(demo.new WriteThread()); es.shutdown();
while(!es.isTerminated()){
;
}
System.out.println("=====================");
/*CopyOnWriteArrayList对象中的最终值*/
System.out.println("eventual " + demo.cowal.toString());
}
}

全部结束后,最终结果和我们预想的一致。

r2 [2, 3, 3]
r1 [2, 4, 3]
=====================
eventual [2, 4, 5]

2. CopyOnWriteArraySet

CopyOnWriteArraySet是一个不存贮重复对象的写时拷贝容器。它的实现的原理很简单,在其内部定义了一个CopyOnWriteArrayList对象al,当向该容器添加一个对象时,会调用addIfAbsent方法。

    public boolean add(E e) {
return al.addIfAbsent(e);
}

3. 参考内容

[1] 聊聊并发-Java中的Copy-On-Write容器 | 并发编程网 – ifeve.com

[2] Java并发编程:并发容器之CopyOnWriteArrayList(转载)

Java并发包中CopyOnWrite容器相关类简介的更多相关文章

  1. Java并发编程(您不知道的线程池操作), 最受欢迎的 8 位 Java 大师,Java并发包中的同步队列SynchronousQueue实现原理

    Java_并发编程培训 java并发程序设计教程 JUC Exchanger 一.概述 Exchanger 可以在对中对元素进行配对和交换的线程的同步点.每个线程将条目上的某个方法呈现给 exchan ...

  2. Java 并发包中的高级同步工具

    Java 并发包中的高级同步工具 Java 中的并发包指的是 java.util.concurrent(简称 JUC)包和其子包下的类和接口,它为 Java 的并发提供了各种功能支持,比如: 提供了线 ...

  3. Java 并发包中的读写锁及其实现分析

    1. 前言 在Java并发包中常用的锁(如:ReentrantLock),基本上都是排他锁,这些锁在同一时刻只允许一个线程进行访问,而读写锁在同一时 刻可以允许多个读线程访问,但是在写线程访问时,所有 ...

  4. Java并发包中常用类小结(一)

    从JDK1.5以后,Java为我们引入了一个并发包,用于解决实际开发中经常用到的并发问题,那我们今天就来简单看一下相关的一些常见类的使用情况. 1.ConcurrentHashMap Concurre ...

  5. Java并发包中Semaphore的工作原理、源码分析及使用示例

    1. 信号量Semaphore的介绍 我们以一个停车场运作为例来说明信号量的作用.假设停车场只有三个车位,一开始三个车位都是空的.这时如果同时来了三辆车,看门人允许其中它们进入进入,然后放下车拦.以后 ...

  6. 【Android 应用开发】Android 网络编程 API笔记 - java.net 包 权限 地址 套接字 相关类 简介

    Android 网络编程相关的包 : 9 包, 20 接口, 103 类, 6 枚举, 14异常; -- Java包 : java.net 包 (6接口, 34类, 2枚举, 12异常); -- An ...

  7. Android 网络编程 API笔记 - java.net 包 权限 地址 套接字 相关类 简介

    Android 网络编程相关的包 : 9 包, 20 接口, 103 类, 6 枚举, 14异常; -- Java包 : java.net 包 (6接口, 34类, 2枚举, 12异常); -- An ...

  8. 优酷电视剧爬虫代码实现一:下载解析视频网站页面(4)补充: Java正则表达式Matcher.group(int group)相关类解析

    在Java正则表达式的相关类Matcher中,有如下几个方法: - int groupCount() - String group(int group) - int start(int group)  ...

  9. Java并发包中Lock的实现原理

    1. Lock 的简介及使用 Lock是java 1.5中引入的线程同步工具,它主要用于多线程下共享资源的控制.本质上Lock仅仅是一个接口(位于源码包中的java\util\concurrent\l ...

随机推荐

  1. angularjs初窥门径

    貌似angularjs出来之后网上各种夸angularjs的好黑jquery. angularjs大致可以分为几个板块:作用域,控制器,指令(主要),路由,依赖注入. 1 作用域 作用域在angula ...

  2. shell基本语法

    一.变量 1.变量的命名规则:以字母或下划线开头,后面跟数字,字母或下划线,最好不要随便命名,要做到看见变量名能猜出其含义 2.变量赋值: x=100 echo $x 删除变量:unset x 3.定 ...

  3. 【NOIP模拟】board(线段树维护二进制,树序号化为二进制)

    题目背景 SOURCE:NOIP2016-RZZ-2 T3 题目描述 给出这样一棵“二叉树”: 每个节点有左右两个儿子,并如下定义每个节点的高度:假设父亲节点的高度为 h ,那么他的两个儿子的节点的高 ...

  4. C++学习(七)入门篇——C++算数运算符

    以下介绍5种C++基本运算符 +.-.×./.% 注意/为第一个数除以第二个数,结果为商的整数部分,小数部分被丢弃 %求模,两个操作数必须是整型,它生成第一个数除以第二个数的余数 如果其中一个是负数, ...

  5. MQ通道搭建以及连通性检查

    场景:项目开发中使用的mq中间件一直不太熟悉,遇到问题就需要问人,公司的同事也不怎么爱搭理,弄的好受伤!不熟悉的时候只是感觉好难,逼的没办法,好好研究下,发现里面的过程也没想象中的难, 经过一番研究, ...

  6. 初学Python(二)——数组

    初学Python(二)——数组 初学Python,主要整理一些学习到的知识点,这次是数组. # -*- coding:utf-8 -*- list = [2.0,3.0,4.0] #计算list长度 ...

  7. Java之IO流补充

    IO流例子 package com.hanqi.maya.util; import java.io.BufferedReader; import java.io.BufferedWriter; imp ...

  8. 53. leetcode557. Reverse Words in a String III

    557. Reverse Words in a String III Given a string, you need to reverse the order of characters in ea ...

  9. Hibernate三大类查询总结

    Hibernate目前总共分为三大类查询:cretiria,hql,本地sql [以下篇章搜集于网络,感谢作者] 第一:关于cretiria的查询 具有一个直观的.可扩展的条件查询API是Hibern ...

  10. 推荐60个jQuery插件(转)

    jQuery插件jQuery Spin Button自定义文本框数值自增或自减 jQuery插件JQuery Pager分页器实现javascript分页功能 jQuery插件FontSizer实现J ...