简介

本文是主要介绍,并发容器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. FZU 2253 salty fish

    https://vjudge.net/problem/FZU-2253 题意:略 思路: 一开始改变区间,还以为是线段树...还是dp的题做得太少了. 这题一开始我们可以统计出一共有多少只翻身的咸鱼, ...

  2. MongoDB的Windows安装

    一.下载MongoDB安装文件 下载地址:http://pan.baidu.com/s/1nvEuDD3 二.双击下载的文件,根据向导一直到finish.比如安装目录为 d:\mongodb 1.创建 ...

  3. Java并发包基石-AQS详解

    目录 1 基本实现原理 1.1 如何使用 1.2 设计思想 2 自定义同步器 2.1 同步器代码实现 2.2 同步器代码测试 3 源码分析 3.1 Node结点 3.2 独占式 3.3 共享式 4 总 ...

  4. (转)log4j(三)——如何控制不同级别的日志信息的输出?

    一:测试环境与log4j(一)——为什么要使用log4j?一样,这里不再重述 1 老规矩,先来个栗子,然后再聊聊感受 package test.log4j.test3; import org.apac ...

  5. angularJS的$http.post请求,.net后台接收不到参数值的解决方案

    JS通用部分 var shoppingCartModule =angular.module('starter', ['ionic'], function ($httpProvider) { // Us ...

  6. vue错误和解决方法

    1.Error in render function: "TypeError: Cannot read property 'matched' of undefined 原因:之前不知道,在引 ...

  7. Redux源码分析之bindActionCreators

    Redux源码分析之基本概念 Redux源码分析之createStore Redux源码分析之bindActionCreators Redux源码分析之combineReducers Redux源码分 ...

  8. 最短路之Floyd算法

    1.介绍 floyd算法只有五行代码,代码简单,三个for循环就可以解决问题,所以它的时间复杂度为O(n^3),可以求多源最短路问题. 2.思想: Floyd算法的基本思想如下:从任意节点A到任意节点 ...

  9. ffmpeg编解码视频导致噪声增大的一种解决方法

    一.前言 ffmpeg在视音频编解码领域算是一个比较成熟的解决方案了.公司的一款视频编辑软件正是基于ffmpeg做了二次封装,并在此基础上进行音视频的编解码处理.然而,在观察编码后的视频质量时,发现图 ...

  10. Alluxio 1.5集群搭建

    一.依赖文件安装 1.1 JDK 参见博文:http://www.cnblogs.com/liugh/p/6623530.html 二.文件准备 2.1 文件名称 alluxio-1.5.0-hado ...