java 线程安全的linkedlist_使ArrayList,LinkedList变成线程安全的

1.使用SynchronizedList

SynchronizedList是一个线程安全的包装类。继承于SynchronizedCollection,SynchronizedCollection实现了Collection接口,SynchronizedList包含一个List对象,对List的访问修改方法进行了一些封装,在封装的方法中会对list使用同步锁加锁,然后再进行存取和修改操作。

使用方法如下

LinkedList linkedList = new LinkedList();

//调用Collections的synchronizedList方法,传入一个linkedList,会返回一个SynchronizedList实例对象

List synchronizedList = Collections.synchronizedList(linkedList);

//调用Collections的synchronizedList方法,ArrayList,返回一个SynchronizedRandomAccessList实例对象

ArrayList arrayList = new ArrayList();

List synchronizedRandomAccessList = Collections.synchronizedList(linkedList);

(Collections.synchronizedList()方法会判断传入的对象是否实现了 RandomAccess接口,是的话,会返回一个SynchronizedRandomAccessList对象,SynchronizedRandomAccessList是SynchronizedList的子类,只是会多一个以线程安全的方式获取子数组的方法)。

SynchronizedList类的部分代码如下:

static class SynchronizedList

extends SynchronizedCollection

implements List {

final List list;//源list

final Object mutex;

SynchronizedCollection(Collection c) {

this.c = Objects.requireNonNull(c);

mutex = this;//mutex就是SynchronizedList实例自己,作为同步锁使用

}

public E get(int index) {

synchronized (mutex) {

是父类中的成员变量,在父类中会将list赋值给mutex

return list.get(index);

}

}

public E set(int index, E element) {

synchronized (mutex) {return list.set(index, element);}

}

}

2.使用CopyOnWriteArrayList

CopyOnWriteArrayList跟ArrayList类似,都是实现了List接口,只不过它的父类是Object,而不是AbstractList。CopyOnWriteArrayList与ArrayList的不同在于,

1.内部持有一个ReentrantLock类型的lock成员变量,

final transient ReentrantLock lock = new ReentrantLock();

在对数组进行修改的方法中,都会先获取lock,获取成功才能进行修改,修改完释放锁,保证每次只允许一个线程对数组进行修改。

2.CopyOnWriteArrayList内部用于存储元素的Object数组使用volatile

//CopyOnWriteArrayList

private transient volatile Object[] array;

//ArrayList

private transient Object[] elementData;//transient

可以看到区别主要在于CopyOnWriteArrayList的Object是使用volatile来修饰的,volatile可以使变量具备内存可见性,一个线程在工作内存中对变量进行修改后,会立即更新到物理内存,并且使得其他线程中的这个变量缓存失效,其他线程在读取会去物理内存中读取最新的值。(volatile修饰的是指向数组的引用变量,所以对数组添加元素,删除元素不会改变引用,所以为了保证内存可见性,CopyOnWriteArrayList.add()方法在添加元素时,都是复制出一个新数组,进行修改操作后,再设置到就数组上)

注意事项:Object数组都使用transient修饰是因为transient修饰的属性不会参与序列化,ArrayList通过实现writeObject()和readObject()方法来自定义了序列化方法(基于反序列化时节约空间考虑,如果用默认的序列方法,源elementData数组长度为100,实际只有10个元素,反序列化时也会分配长度为100的数组,造成内存浪费。)

public boolean add(E e) {

final ReentrantLock lock = this.lock;

//1. 使用Lock,保证写线程在同一时刻只有一个

lock.lock();

try {

//2. 获取旧数组引用

Object[] elements = getArray();

int len = elements.length;

//3. 创建新的数组,并将旧数组的数据复制到新数组中

Object[] newElements = Arrays.copyOf(elements, len + 1);

//4. 往新数组中添加新的数据

newElements[len] = e;

//5. 将旧数组引用指向新的数组

setArray(newElements);

return true;

} finally {

lock.unlock();

}

}

3.SynchronizedList和CopyOnWriteArrayList优缺点

SynchronizedList是通过对读写方法使用synchronized修饰来实现同步的,即便只是多个线程在读数据,也不能进行,如果是读比较多的场景下,会性能不高,所以适合读写均匀的情况。

而CopyOnWriteArrayList是读写分离的,只对写操作加锁,但是每次写操作(添加和删除元素等)时都会复制出一个新数组,完成修改后,然后将新数组设置到旧数组的引用上,所以在写比较多的情况下,会有很大的性能开销,所以适合读比较多的应用场景。

原创文章,作者:9IM,如若转载,请注明出处:https://www.9im.cn/500.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/540994.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人工智能能够构建一个自主驱动云吗?

企业和组织可以从云计算中受益,但许多公司并不希望面对公共云的成本,性能和治理问题,并且认为构建自己的私有云的复杂性和运营开销并没有那么困难。 如今,一些云计算供应商正在使用人工智能(AI)来简化私有云…

scala中def_def关键字以及Scala中的示例

scala中defScala def关键字 (Scala def keyword) The def keyword in Scala is used to declare functions and methods in Scala. Scala being ignorant on the data types does the same with the return type of a function. Declaring and defining a function in Scala do…

前端必备的 web 安全知识手记

前言 安全这种东西就是不发生则已,一发生则惊人。作为前端,平时对这方面的知识没啥研究,最近了解了下,特此沉淀。文章内容包括以下几个典型的 web 安全知识点:XSS、CSRF、点击劫持、SQL 注入和上传问题等(…

php脚本开头注释_PHP文件注释标记及规范小结

PHP文件注释标记及规范小结发布时间:2016-06-17 来源: 点击:次PHP 注释标记access使用范围:class,function,var,define,module该标记用于指明关键字的存取权限:private、public或protecedauthor指明作者copyright使用范围&#xf…

Salesforce宣布5.82亿美元收购文件编辑公司Quip

北京时间8月2日消息,据路透社报道,云软件开发商Salesforce.com周一宣布,已同意以大约5.82亿美元收购文件编辑创业公司Quip。 Salesforce此前已经对Quip进行了投资。Quip开发的文字处理平台供企业员工用于在移动设备、可穿戴设备以及台式机上编…

Java中的main()方法是强制性的吗?

The question is that "Is main() method is compulsory in Java?" 问题是“ main()方法在Java中是强制性的吗?” Yes, we can write a java program without main() method but there is a condition if and only if java JDK version till JDK 5. 是的…

php date( w ),PHP Date()函数详解

页面的最上方加上:date_default_timezone_set(PRC); /*把时间调到北京时间,php5默认为格林威治标准时间*/date ()a: "am"或是"pm"A: "AM"或是"PM"d: 几日,两位数字,若不足则补零&#xff1b…

10.6-全栈Java笔记:常见流详解(四)

上节我们讲到「Java中常用流:数据流和对象流」,本节我们学习文件字符流和文件缓冲流~文件字符流前面介绍的文件字节流可以处理所有的文件,但是字节流不能很好的处理Unicode字符,经常会出现“乱码”现象。所以,我们处理…

python 示例_带有示例的Python File open()方法

python 示例文件open()方法 (File open() Method) open() method is an inbuilt method in Python, it is used to create, open or append a file. open()方法是Python中的内置方法,用于创建,打开或附加文件。 Syntax: 句法: file_object …

php属于脚本,php是脚本语言吗

PHP即“超文本预处理器”,是一种通用开源脚本语言。PHP是在服务器端执行的脚本语言,与C语言类似,是常用的网站编程语言。PHP独特的语法混合了C、Java、Perl以及 PHP 自创的语法。利于学习,使用广泛,主要适用于Web开发领…

NetMarketShare:本月桌面浏览器市场份额几乎没有变化

NetMarketShare之前关于台式机浏览器市场份额的报告表示,Google Chrome市场份额正在快速上升,而Edge浏览器市场份额正在以蜗牛的速度前进。而该公司的最新统计数据显示,几乎所有浏览器的市场份额或多或少保持不变。 NetMarketShare的最新统计…

treeset java_Java TreeSet add()方法与示例

treeset javaTreeSet类的add()方法 (TreeSet Class add() method) add() method is available in java.util package. add()方法在java.util包中可用。 add() method is used to add the given object(ob) to this TreeSet when it does not already exist otherwise it ignore…

php fpm www.conf,PHP7中php.ini、php-fpm和www.conf 配置

PHP7中php.ini、php-fpm和www.conf 配置php.ini是php运行核心配置文件,下面是一些常用配置extension_dir""● 设置PHP的扩展库路径expose_php Off● 避免PHP信息暴露在http头中display_errors Off● 避免暴露php调用mysql的错误信息log_errors On● 在关闭display…

服务器电流源泉ups电源的三大形式

还记得此前12306官网瘫痪,回家心切急于购票的我们只能感到无比心累。双十一前夕,守在购物车边准备疯狂购物的剁手党们,遇到一直呈现加载状态的页面,不得不感叹想要做马云背后的那个人也要大费周折。作为一个资深网民,不…

timer purge_Java Timer purge()方法与示例

timer purge计时器类purge()方法 (Timer Class purge() method) purge() method is available in java.util package. purge()方法在java.util包中可用。 purge() method is used to remove all canceled tasks from the task queue of this Timer. purge()方法用于从此Timer的…

大话Linux内核中锁机制之原子操作、自旋锁【转】

转自:http://blog.sina.com.cn/s/blog_6d7fa49b01014q7p.html 多人会问这样的问题,Linux内核中提供了各式各样的同步锁机制到底有何作用?追根到底其实是由于操作系统中存在多进程对共享资源的并发访问,从而引起了进程间的竞态。这…

hashmap put方法_Java HashMap put()方法与示例

hashmap put方法HashMap类的put()方法 (HashMap Class put() method) put() method is available in java.util package. put()方法在java.util包中可用。 put() method is used to link the given value element with the given key element in this HashMap. put()方法用于在…

java中jdom,java – JDOM中的命名空间(默认)

我正在尝试使用最新的JDOM包生成XML文档.我遇到了根元素和命名空间的问题.我需要生成这个根元素:xmlns"http://www.energystar.gov/manageBldgs/req"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://www.…

java enummap_Java EnumMap get()方法与示例

java enummapEnumMap类的get()方法 (EnumMap Class get() method) get() method is available in java.util package. get()方法在java.util包中可用。 get() method is used to get the value mapped with the given key element (key_ele) otherwise it returns null when no…

java后台json传递,后台json传递

json除了可以用于前台传递,还可用于后台之间传递。它可以传递List,Map,Bean等类型的数据。例如:User u1new User();u1.setUsername("zy");u1.setPassword("123");User u2new User();u2.setUsername("msl");u2.setPassword…