简介

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

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

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


1. CopyOnWriteArrayList

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

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

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

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

下面是写操作源代码

  1. public E set(int index, E element) {
  2. final ReentrantLock lock = this.lock;
  3. lock.lock();
  4. try {
  5. Object[] elements = getArray();
  6. E oldValue = get(elements, index);
  7.  
  8. if (oldValue != element) {
  9. int len = elements.length;
  10. Object[] newElements = Arrays.copyOf(elements, len);
  11. newElements[index] = element;
  12. setArray(newElements);
  13. } else {
  14. // Not quite a no-op; ensures volatile write semantics
  15. setArray(elements);
  16. }
  17. return oldValue;
  18. } finally {
  19. lock.unlock();
  20. }
  21. }

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

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

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

  1. package javalearning;
  2.  
  3. import java.util.Random;
  4. import java.util.concurrent.CopyOnWriteArrayList;
  5. import java.util.concurrent.ExecutorService;
  6. import java.util.concurrent.Executors;
  7.  
  8. /*CopyOnWriteArrayList演示例程*/
  9. public class CopyOnWriteArrayListDemo {
  10. /*定义一个CopyOnWriteArrayList对象,读线程和写线程会同时使用它*/
  11. private CopyOnWriteArrayList<Integer> cowal = new CopyOnWriteArrayList<Integer>();
  12. {
  13. /*对CopyOnWriteArrayList对象初始化*/
  14. cowal.add(1);
  15. cowal.add(2);
  16. cowal.add(3);
  17. }
  18.  
  19. private Random rnd = new Random();
  20.  
  21. public class ReadThread implements Runnable{
  22. private String id;
  23.  
  24. public ReadThread(String id){
  25. this.id = id;
  26. }
  27.  
  28. @Override
  29. public void run() {
  30. try {
  31. Thread.sleep(rnd.nextInt(1000));
  32. } catch (InterruptedException e) {
  33. e.printStackTrace();
  34. }
  35. /*读线程会打印出CopyOnWriteArrayList对象的所有数值*/
  36. System.out.println(id + " " + cowal.toString());
  37. }
  38.  
  39. }
  40.  
  41. public class WriteThread implements Runnable{
  42.  
  43. /*写线程会将CopyOnWriteArrayList对象的所有数值加1*/
  44. @Override
  45. public void run() {
  46. for(int i = 0; i < cowal.size(); i++){
  47. int x = cowal.get(i);
  48.  
  49. /*每修改一个元素之前加锁*/
  50. cowal.set(i, x+1);
  51. /*修改完一个元素后释放锁*/
  52.  
  53. try{
  54. Thread.sleep(rnd.nextInt(1000));
  55. }catch(InterruptedException e){
  56. e.printStackTrace();
  57. }
  58. }
  59. }
  60.  
  61. }
  62.  
  63. public static void main(String[] args){
  64. ExecutorService es = Executors.newCachedThreadPool();
  65. CopyOnWriteArrayListDemo demo = new CopyOnWriteArrayListDemo();
  66. /*创建两个读线程*/
  67. es.execute(demo.new ReadThread("r1"));
  68. es.execute(demo.new ReadThread("r2"));
  69. /*创建两个写线程*/
  70. es.execute(demo.new WriteThread());
  71. es.execute(demo.new WriteThread());
  72.  
  73. es.shutdown();
  74. while(!es.isTerminated()){
  75. ;
  76. }
  77. System.out.println("=====================");
  78. /*CopyOnWriteArrayList对象中的最终值*/
  79. System.out.println("eventual " + demo.cowal.toString());
  80. }
  81. }

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

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

2. CopyOnWriteArraySet

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

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

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. vue mint UI

    vue 与mint  UI 结合开发手机app  html5页面 api  文档   http://mint-ui.github.io/#!/zh-cn

  2. 关于sessionStorage的移动端兼容问题

    最近在开发移动端项目时,需要用到的本地存储的地方不少.都是一些只要记住当前打开窗口的用户数据就行,所以我选择用的sessionStorage.使用场景如下: A.html页面需要记录一条数据{a:1, ...

  3. hdu_1506:Largest Rectangle in a Histogram 【单调栈】

    题目链接 对栈的一种灵活运用吧算是,希望我的注释写的足够清晰.. #include<bits/stdc++.h> using namespace std; typedef long lon ...

  4. nyoj_1022:合纵连横(并查集删点)

    题目链接 参考链接 只附代码好了 #include<bits/stdc++.h> using namespace std; ; int a[N],b[N],vis[N]; int n,m, ...

  5. 【tyvj1463】智商问题 [分块][二分查找]

    Background 各种数据结构帝~各种小姊妹帝~各种一遍AC帝~ 来吧! Description 某个同学又有很多小姊妹了他喜欢聪明的小姊妹 所以经常用神奇的函数来估算小姊妹的智商他得出了自己所有 ...

  6. [编辑器]vim常用操作

    我是ide的用户,对于vim一只停留在:打开.看.写.关闭基本操作,因为现在更多的接触linux服务器,所以为了提高 效率,用好vim是必备技能!下面罗列一些vim的常用操作,用做备忘(不断更新): ...

  7. 分页功能的实现——Jdbc && JSP

    @目录 什么是分页 ? 两个子模块功能的问题分析 和 解决方案 有条件查和无条件查询的影响 和 解决方案 项目案例: mysql + commons-dbutils+itcast-tools+Base ...

  8. 【ES6】变量的解构赋值

    1. 数组 var [a, b, c] = [1, 2, 3]; let [a, [b], d] = [1, [2, 3], 4]; 默认值生效的条件是,对象的属性值严格等于undefined. [x ...

  9. [补档]Cube

    Cube 题目 给你一个n×m的棋盘,有一个1×1×2的长方体竖直放在(1,1)上,你可以将其在棋盘上滚动,你的目标是让其竖直放在(n,m)上,问至少需要多少次操作.(放倒.竖直.翻滚) INPUT ...

  10. 49. leetcode 94. Binary Tree Inorder Traversal

    94. Binary Tree Inorder Traversal    二叉树的中序遍历 递归方法: 非递归:要借助栈,可以利用C++的stack