技术标签: Java java CopyOnWrite CopyOnWriteArraySet CopyOnWriteArrayList
CopyOnWriteArrayList
可以看成是ArrayList的线程安全版本,所以很多方面与ArrayList相同,我们略过一些相同的方面,先来看其主要属性 /** 可重入锁,用来保证写安全 */
transient final ReentrantLock lock = new ReentrantLock();
/** volatile数组.确保 set的时候修改引用地址的时候是原子操作 */
private volatile transient Object[] array;
/**
* 通过 set一个空Object数组进行初始化
*/
public CopyOnWriteArrayList() {
setArray(new Object[0]);
}
/**
* 对于非Object类的, 转换为Object数组.再set
*/
public CopyOnWriteArrayList(Collection<? extends E> c) {
Object[] elements = c.toArray();
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elements.getClass() != Object[].class)
elements = Arrays.copyOf(elements, elements.length, Object[].class);
setArray(elements);
}
/**
* 将传入的array复制为 Object数组
*/
public CopyOnWriteArrayList(E[] toCopyIn) {
setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
}
@SuppressWarnings("unchecked")
private E get(Object[] a, int index) {
return (E) a[index];
}
public E get(int index) {
return get(getArray(), index);
}
/**
*/
public int indexOf(Object o) {
Object[] elements = getArray();
return indexOf(o, elements, 0, elements.length);
}
/**
* 通过遍历数组来确定位置.
*/
private static int indexOf(Object o, Object[] elements,
int index, int fence) {
if (o == null) {
for (int i = index; i < fence; i++)
if (elements[i] == null)
return i;
} else {
for (int i = index; i < fence; i++)
if (o.equals(elements[i]))
return i;
}
return -1;
}
/**通过indexOf来确定是否包含.
*/
public boolean contains(Object o) {
Object[] elements = getArray();
return indexOf(o, elements, 0, elements.length) >= 0;
}
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
final ReentrantLock lock = this.lock;
lock.lock(); //加锁. 防止同时有两个写线程进入.
try {
Object[] elements = getArray(); // 得到array的引用.
int len = elements.length; //判断 index是否合理.
if (index > len || index < 0)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+len);
Object[] newElements; //定义新数组.
int numMoved = len - index; //需要移动的元素数量. 即.index之后的元素都需要移动一个位置.
if (numMoved == 0) //插到最后.
newElements = Arrays.copyOf(elements, len + 1); //copy原数组,并设置copy后的新数组长度为 原数组长度+1.
else {
newElements = new Object[len + 1]; //新数组比原数组多一个元素
System.arraycopy(elements, 0, newElements, 0, index); //copy前段.
System.arraycopy(elements, index, newElements, index + 1,
numMoved); //copy index之后的后段.
}
newElements[index] = element; //在目标位置设值.
setArray(newElements); //将 完成写操作之后的数组刷新到引用中.
} finally {
lock.unlock(); //写操作完毕解锁.
}
}
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();
}
}
public E remove(int index) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
E oldValue = get(elements, index);
int numMoved = len - index - 1;
if (numMoved == 0)
setArray(Arrays.copyOf(elements, len - 1));
else {
Object[] newElements = new Object[len - 1];
System.arraycopy(elements, 0, newElements, 0, index);
System.arraycopy(elements, index + 1, newElements, index,
numMoved);
setArray(newElements);
}
return oldValue;
} finally {
lock.unlock();
}
}
synchronized
, 这样子就保证了多个线程调用这些写操作时安全。Arrays.copyOf
和 System.arraycopy
。 首先,Arrays.copyOf
本质上, 调用的还是System.arrayCopy的方法, 而System.arrayCopy
则是使用native代码(基于内存块的拷贝),从而使数组拷贝尽量快。add
方法, if 里使用Arrays.copy
而else使用System.arraycopy
而不使用 Arrays.copyRange
。 我认为是因为在Arrays.copyRange
里加了一些范围之类的检查,而在这里是没有必要的,因此这里使用System.arraycopy
可以减少检查,效率更高.copy
, 只用了写lock, 只能保证写的安全,如果不用copy读是不安全的。lock
的(但是lock了话就和Vector
或Collections.synchronizedList
没有太大区别了),如果不copy, 会造成同时读写有问题。在上面,我们发现, 写的时候不单有锁,并且还会进行copy, 可以发现:
另外,CopyOnWrite这里还有一个类, CopyOnWriteArraySet
不重复元素的集合, 其底层其实使用 CopyOnWriteArrayList
, 所以基本和CopyOnWriteArrayList
一样的, 可以自行浏览一下源码。
文章浏览阅读1k次。本文由中山大学人机物智能融合实验室(HCP Lab)特约供稿。全球计算机视觉三大顶会之一CVPR 2019(IEEE Conference on Computer Visionand Pattern Recognition) 于 6月 16~20日 在美国洛杉矶如期举办。CVPR 作为计算机视觉三大顶级会议之一,一直以来都备受关注。被 CVPR 收录的论文更是代表了计算机视觉领域的最新发展...
文章浏览阅读4.7k次,点赞8次,收藏9次。安装又按不了->更新又不行->怎么办gcc程序“gcc”尚未安装。 您可以使用以下命令安装:sudo apt-get install gccweifc@ubuntu:~/demo$ sudo apt-get install gcc正在读取软件包列表… 完成正在分析软件包的依赖关系树正在读取状态信息… 完成现在没有可用的软件包 gcc,但是它被其它的软件包引用了。这可能..._没有可用的软件包 gcc-multilib,但是它被其它的软件包引用了。 这可能意味着这个
文章浏览阅读2.7k次。首先,到http://rxtx.qbang.org/wiki/index.php/Download下载相应zip包,由于发帖时2.2版本不稳定(里面是jar是2.1版本,但dll是2.2版本,造成版本冲突,报错:RXTX Version mismatch),建议使用2.1-7r2版本。请参见本博客另一篇博文点击打开链接,将zip中的jar安装到maven仓库里。在pom文件中加入引用。_rxtx version mismatch
文章浏览阅读299次。传统上,我们通过替换当前版本来部署新版本。 旧版本停止了,新版本被替换了。 这种方法的问题是从旧版本停止运行到新版本完全运行之间的停机时间。 无论您尝试执行此过程的速度如何,都会有一些停机时间。 那可能只有一毫秒,也可能持续数分钟,在极端情况下甚至可能长达数小时。 具有整体式应用程序会带来其他问题,例如,需要等待相当长的时间才能初始化应用程序。 人们试图以各种方式解决此问题,并且大多数人使用..._不可变部署 蓝绿部署
文章浏览阅读751次。/** * 获取当前系统的版本名称 * @return */ public String getSystemVersionName(){ String ver = null; try { systemProperties_get = Class.forName(&quot;android.os.System..._android userhandle.system需反射获取
文章浏览阅读2w次,点赞14次,收藏56次。1,sleep方法是Thread类的静态方法,wait()是Object超类的成员方法 2,sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。在调用sleep()方法的过程中,线程不会释放对象锁。而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notif..._sleep和wait
文章浏览阅读2.2k次,点赞2次,收藏8次。普通安装1.拉取镜像,redis:4.0docker pull redis:4.02.创建redis容器名"redistest1",并开启持久化docker run -d -p 6379:6379 --name redistest1 redis:4.0 redis-server --appendonly yes参数说明:--appendonly yes:开启持久化挂载外部配置和数据安装1.创建目录和配置文件redis.confmkdir /dockermk_docker run -p 6379:6379 \ -v /root/docker/redis/redis.conf:/etc/redis/redis.
文章浏览阅读655次。单行函数 Function name(column | expression,[arg0,arg1,arg2….]) 单行函数的分类: 字符函数:接受字符串的输入并返回字符串的值 数值函数:接受数值的输入并返回数值 日期函数:对日期数据进行操作 转换函数:从一种数据类型转换成另一种类_193500大写
文章浏览阅读5.4k次,点赞4次,收藏17次。1.Android studio的安装百度搜索Android studio官网下载速度会比较慢,所以我们选择中文社区在这里选择要下载的版本,我选择的是Windows3.5.2版本下载完成之后双击安装,这里要注意,因为一般情况下我们都是用Java编程,所以安装的时候尽量选择和jdk同一个盘下。而且安装路径尽量不要出现中文,容易报错。然后一路next+finish。..._andriod端下载
文章浏览阅读5.3k次。在Duilib程序中,在xml中如果有加载资源文件(比如png背景图片),如果调试程序是出现黑屏,加载资源失败,但是单独执行exe文件是可以的,这是很可能是因为资源文件的位置放的不对,你可能释放到xml相同的目录,但是程序实际上加载资源文件实在项目的当前目录,把资源文件放到项目的当前目录就是可以的,这样虽然是可以的,但是感觉不太符合要求,如果需要在指定的位置加载资源文件,可以使用以下代码来设置:_vs 本地资源运行不起来,exe可以运行
文章浏览阅读3.8k次。最近在写游戏的时候,遇到了一些奇怪的问题,由于之前写的都比较顺利,从来没有调试过代码,直到现在才发现学习 Cocos Creator 这几个月以来竟然从来没有调试过代码,于是赶紧研究了一下,发现经常用到的大概就两种:VS Code + Chrome 和 Chrome,今天就来简单的记录一下,方便和我一样不会调试的小伙伴了解一下。第一种:VS Code + Chrome1.首先创建一个 Hell..._cocos打断点
文章浏览阅读224次。https://www.cnblogs.com/silence-cho/p/10926248.html(一)OpenCV-Python学习—基础知识_openmv供电怎么接线