简介

本文是主要介绍,并发容器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. Ubuntu14.04桌面系统允许root登录

    首先安装完系统后,在登录界面我们可以看到不允许root账户登录.以普通账户登录系统,打开终端.执行如下命令来设置root密码: sudo passwd root 然后执行命令修改如下配置文件: vi ...

  2. nyoj_471:好多的树(容斥原理)

    题目链接: http://acm.nyist.net/JudgeOnline/problem.php?pid=471 还是直接上代码.. #include<bits/stdc++.h> u ...

  3. 学习笔记TF031:实现VGGNet

    VGGNet,牛津大学计算机视觉组(Visual Geometry Group)和Google DeepMind公司一起研发,深度卷积神经网络.VGGNet反复堆叠3x3小型卷积核和2x2最大池化层, ...

  4. STS 配置tomcat以后,无法访问

    问题 今天在新环境下安装开发环境STS,使用的的3.9,如下图 安装完成之后配置Tomcat,在STS启动Tocat后,在浏览器输入:http://localhost:8080/ 发现无法访问... ...

  5. 【highchart】经典问题

    摘要 记录遇到的一些问题和解决方案 时差 数据容量 多表联动 1. 时差 问题描述 highcharts 默认是标准 UTC 时间,而国内默认是东八区时间,所以会有8个小时的时差 解决方法 使用hig ...

  6. 给ubuntu的swap分区增加容量

    1.创建一个 Swap 文件. mkdir swap cd swap sudo dd if=/dev/zero of=swapfile bs=1024 count=100000 出现下列提示,上面命令 ...

  7. Linux下软件的卸载

    一.rpm -q -a 查看所安的全部软件 二.#rpm -e [package name]  卸载想要卸载的软件  

  8. github 上传下载代码简单使用

    很长时间,一直认为github很难操作,其实认真学了发现也不是很困难. 主要就3个命令 git clone 建立空间 git push 提交代码,git pull拉取代码. git clone htt ...

  9. ios扫雷

    就这些代码敲了我两个小时...... //  ViewController.m //  扫雷 // //  Created by 晚起的蚂蚁 on 2017/3/22. //  Copyright © ...

  10. ABP+AdminLTE+Bootstrap Table权限管理系统第八节--ABP错误机制及AbpSession相关

    上一节我们讲到登录逻辑,我做的登录逻辑很简单的,我们来看一下abp module-zero里面的登录代码. #region Login / Logout public ActionResult Log ...