collections.synchronized同步方法list能保证同步吗

Collections Collections.synchronizedCollection 集合的同步控制
Collections Collections.synchronizedCollection 集合的同步控制。
Collections类中提供了多个synchronizedXxx方法:
该方法返回指定集合对象对应的同步对象,解决多线程并发访问集合时线程的安全问题
最常用的集合类有List、Set、Map等,而集合框架中经常使用的三个实现类: HashSet、ArrayList、HashMap都是线程不安全的,Collections提供了多个静态方法用于创建同步集合:
Collection c = Collections.synchronizedCollection(new ArrayList());
List list = Collections.synchronizedList(new ArrayList());
Set set = Collections.synchronizedSet(new HashSet());
Map map = Collections.synchronizedMap(new HashMap());
static class SynchronizedCollection implements Collection, Serializable {
// use serialVersionUID from JDK 1.2.2 for interoperability
private static final long serialVersionUID = 1335093L;
final Collection
// Backing Collection
// Object on which to synchronize
SynchronizedCollection(Collection c) {
if (c==null)
throw new NullPointerException();
SynchronizedCollection(Collection c, Object mutex) {
this.mutex =
java.util.Collections.synchronizedCollection()方法的声明。
public static Collection synchronizedCollection(Collection c)
功能:方法用于获得同步的(线程安全的)集合的指定集合的支持
参数c: 在同步集合的被&包装&的集合
在方法调用返回指定集合的同步视图。
static class SynchronizedRandomAccessList extends SynchronizedList
implements RandomAccess {
static final long serialVersionUID = 2358482L;
SynchronizedRandomAccessList(List list) {
super(list);
SynchronizedRandomAccessList(List list, Object mutex) {
super(list, mutex);
public List subList(int fromIndex, int toIndex) {
synchronized(mutex) {
return new SynchronizedRandomAccessList(list.subList(fromIndex, toIndex), mutex);
private Object writeReplace() {
return new SynchronizedList(list);
java.util.Collections.synchronizedList()方法的声明:
public static
List synchronizedList(List list) {
return (list instanceof RandomAccess ?
new SynchronizedRandomAccessList(list) :
new SynchronizedList(list));//根据不同的list类型最终实现不同的包装类。
返回列表的同步(线程安全的)列表,对线程安全的List对象,当线程访问时,需获取到该对象的锁才能进行(而不管它是否处于synchronized 同步块中)。
参数list:
需转换成线程安全的列表
当有一个线程获取到该对象的锁后,那么其他线程无论是否使用syn同步块,在调用add,remove等方法时,都会等待获取锁的线程执行完毕后才执行
SynchronizedList对部分操作加上了synchronized关键字以保证线程安全。但其iterator()操作还不是线程安全的(SynchronizedList适合不需要使用Iterator的多线程使用环境)。部分SynchronizedList的代码如下:
public E get(int index) {
synchronized(mutex) {return list.get(index);}
public E set(int index, E element) {
synchronized(mutex) {return list.set(index, element);}
public void add(int index, E element) {
synchronized(mutex) {list.add(index, element);}
public ListIterator listIterator() {
return list.listIterator(); // Must be manually synched by user,否则仍然可能抛出ConcurrentModificationException
public ListIterator listIterator(int index) {
return list.listIterator(index); // Must be manually synched by user,否则仍然可能抛出ConcurrentModificationException
//SynchronizedMap类是定义在Collections中的一个静态内部类。它实现了Map接口,并对其中的每一个方法实现,通过synchronized 关键字进行了同步控制
public static
Map synchronizedMap(Map m) {
return new SynchronizedMap(m);
mutex就是当前的SynchronizedCollection对象,而SynchronizedRandomAccessList继承自SynchronizedList,SynchronizedList又继承自SynchronizedCollection,所以SynchronizedRandomAccessList中的mutex也就是SynchronizedRandomAccessList的this对象
1、Collections.synchronizedCollection()
// create vector object
Vector vector = new Vector();
vector.add(&1&);
// create a synchronized view
Collection c = Collections.synchronizedCollection(vector);
System.out.println(&Synchronized view is :&+c);
2、Collections.synchronizedList()
List list = Collections.synchronizedList(new ArrayList()); //ArrayList是非线性安全,此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的
synchronized (list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
System.out.println(&list: &+i.next());
// create List object
List list = new ArrayList(); //在创建迭代器之后,除非通过迭代器自身的 remove 或 add 方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器都会抛出 ConcurrentModificationException
list.add(&1&); // add first item
// create a synchronized list
List synlist = Collections.synchronizedList(list); //synlist就是线程安全的List 对象
new Thread(){
public void run() {
synchronized (synlist) {
Thread.sleep(100);
catch (InterruptedException e) {
synlist.add(&2&);
System.out.println(&Operation1 synlist: &+synlist.size() + &, synlist item2: &+synlist.get(2));
}.start();
new Thread(){
public void run() {
synlist.add(&3&);
System.out.println(&Operation2 synlist: &+synlist.size()+&, synlist item2: &+synlist.get(2));
}.start();
3、Collections.synchronizedMap()
Map map = Collections.synchronizedMap(new TreeMap());
map.put(&key1&,&value1&);
map.put(&key2&,&value2&);
Set<entry& entries = map.entrySet();
Iterator<entry& iter = entries.iterator();
synchronized (map) {
while(iter.hasNext()){
System.out.println(iter.next());
//迭代元素时可能会抛出ConcurrentModificationException异常,所以可加上同步机制synchronized
map.remove(&key2&);
}</entry</entryJava多线程(9)
当一个类已经很好的同步以保护它的数据时,这个类就称为“线程安全的”。
即使是线程安全类,也应该特别小心,因为操作的线程是间仍然不一定安全。
举个形象的例子,比如一个集合是线程安全的,有两个线程在操作同一个集合对象,当第一个线程查询集合非空后,删除集合中所有元素的时候。第二个线程也来执行与第一个线程相同的操作,也许在第一个线程查询后,第二个线程也查询出集合非空,但是当第一个执行清除后,第二个再执行删除显然是不对的,因为此时集合已经为空了。
看个代码:
public&class&NameList {&
&&&&private&List nameList = Collections.synchronizedList(new&LinkedList());&
&&&&public&void&add(String name) {&
&&&&&&&&nameList.add(name);&
&&&&public&String removeFirst() {&
&&&&&&&&if&(nameList.size() & 0) {&
&&&&&&&&&&&&return&(String) nameList.remove(0);&
&&&&&&&&}&else&{&
&&&&&&&&&&&&return&null;&
&&&&&&&&}&
public&class&Test {&
&&&&public&static&void&main(String[] args) {&
&&&&&&&&final&NameList nl =&new&NameList();&
&&&&&&&&nl.add(&aaa&);&
&&&&&&&&class&NameDropper&extends&Thread{&
&&&&&&&&&&&&public&void&run(){&
&&&&&&&&&&&&&&&&String name = nl.removeFirst();&
&&&&&&&&&&&&&&&&System.out.println(name);&
&&&&&&&&&&&&}&
&&&&&&&&}&
&&&&&&&&Thread t1 =&new&NameDropper();&
&&&&&&&&Thread t2 =&new&NameDropper();&
&&&&&&&&t1.start();&
&&&&&&&&t2.start();&
&运行结果:
虽然集合对象
&&& private List nameList = Collections.synchronizedList(new LinkedList());
是同步的,但是程序还不是线程安全的。
出现这种事件的原因是,上例中一个线程操作列表过程中无法阻止另外一个线程对列表的其他操作。
解决上面问题的办法是,在操作集合对象的NameList上面做一个同步。改写后的代码如下:
public&class&NameList {&
&&&&private&List nameList = Collections.synchronizedList(new&LinkedList());&
&&&&public&synchronized&void&add(String name) {&
&&&&&&&&nameList.add(name);&
&&&&public&synchronized&String removeFirst() {&
&&&&&&&&if&(nameList.size() & 0) {&
&&&&&&&&&&&&return&(String) nameList.remove(0);&
&&&&&&&&}&else&{&
&&&&&&&&&&&&return&null;&
&&&&&&&&}&
这样,当一个线程访问其中一个同步方法时,其他线程只有等待。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:5785次
排名:千里之外
原创:14篇
转载:11篇
(1)(1)(1)(1)(1)(5)(15)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'CopyOnWriteArrayList与Collections.synchronizedList的性能对比 - CSDN博客
CopyOnWriteArrayList与Collections.synchronizedList的性能对比
& & & & 列表实现有ArrayList、Vector、CopyOnWriteArrayList、Collections.synchronizedList(list)四种方式。
1 ArrayList
& & & & ArrayList是非线性安全,此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的:在创建迭代器之后,除非通过迭代器自身的 remove 或 add 方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器都会抛出 ConcurrentModificationException。即在一方在便利列表,而另一方在修改列表时,会报ConcurrentModificationException错误。而这不是唯一的并发时容易发生的错误,在多线程进行插入操作时,由于没有进行同步操作,容易丢失数据。
public boolean add(E e) {
ensureCapacity(size + 1);
// Increments modCount!!
elementData[size++] =//使用了size++操作,会产生多线程数据丢失问题。
}& & & & 因此,在开发过程当中,ArrayList并不适用于多线程的操作。
& & & & 从JDK1.0开始,Vector便存在JDK中,Vector是一个线程安全的列表,采用数组实现。其线程安全的实现方式是对所有操作都加上了synchronized关键字,这种方式严重影响效率,因此,不再推荐使用Vector了,Stackoverflow当中有这样的描述:。
3&Collections.synchronizedList & CopyOnWriteArrayList
& & & &CopyOnWriteArrayList和Collections.synchronizedList是实现线程安全的列表的两种方式。两种实现方式分别针对不同情况有不同的性能表现,其中CopyOnWriteArrayList的写操作性能较差,而多线程的读操作性能较好。而Collections.synchronizedList的写操作性能比CopyOnWriteArrayList在多线程操作的情况下要好很多,而读操作因为是采用了synchronized关键字的方式,其读操作性能并不如CopyOnWriteArrayList。因此在不同的应用场景下,应该选择不同的多线程安全实现类。
3.1 Collections.synchronizedList
& & & &&Collections.synchronizedList的源码可知,其实现线程安全的方式是建立了list的包装类,代码如下:
public static &T& List&T& synchronizedList(List&T& list) {
return (list instanceof RandomAccess ?
new SynchronizedRandomAccessList&T&(list) :
new SynchronizedList&T&(list));//根据不同的list类型最终实现不同的包装类。
}其中,SynchronizedList对部分操作加上了synchronized关键字以保证线程安全。但其iterator()操作还不是线程安全的。部分SynchronizedList的代码如下:
public E get(int index) {
synchronized(mutex) {return list.get(index);}
public E set(int index, E element) {
synchronized(mutex) {return list.set(index, element);}
public void add(int index, E element) {
synchronized(mutex) {list.add(index, element);}
public ListIterator&E& listIterator() {
return list.listIterator(); // Must be manually synched by user 需要用户保证同步,否则仍然可能抛出ConcurrentModificationException
public ListIterator&E& listIterator(int index) {
return list.listIterator(index); // Must be manually synched by user &span style=&font-family: Arial, Helvetica, sans-&&需要用户保证同步,否则仍然可能抛出ConcurrentModificationException&/span&
3.2 CopyOnWriteArrayList
& & & & 从字面可以知道,CopyOnWriteArrayList在线程对其进行些操作的时候,会拷贝一个新的数组以存放新的字段。其写操作的代码如下:
/** The lock protecting all mutators */
transient final ReentrantLock lock = new ReentrantLock();
/** The array, accessed only via getArray/setArray. */
private volatile transient Object[]//保证了线程的可见性
public boolean add(E e) {
final ReentrantLock lock = this.//ReentrantLock&#160;保证了线程的可见性和顺序性,即保证了多线程安全。
lock.lock();
Object[] elements = getArray();
int len = elements.
Object[] newElements = Arrays.copyOf(elements, len + 1);//在原先数组基础之上新建长度+1的数组,并将原先数组当中的内容拷贝到新数组当中。
newElements[len] =//设值
setArray(newElements);//对新数组进行赋值
} finally {
lock.unlock();
}& & & & 其读操作代码如下:
public E get(int index) {
return (E)(getArray()[index]);
}& & & & 其没有加任何同步关键字,根据以上写操作的代码可知,其每次写操作都会进行一次数组复制操作,然后对新复制的数组进行些操作,不可能存在在同时又读写操作在同一个数组上(不是同一个对象),而读操作并没有对数组修改,不会产生线程安全问题。Java中两个不同的引用指向同一个对象,当第一个引用指向另外一个对象时,第二个引用还将保持原来的对象。
& & & & 其中setArray()操作仅仅是对array进行引用赋&#20540;。Java中“=”操作只是将引用和某个对象关联,假如同时有一个线程将引用指向另外一个对象,一个线程获取这个引用指向的对象,那么他们之间不会发生ConcurrentModificationException,他们是在虚拟机层面阻塞的,而且速度非常快,是一个原子操作,几乎不需要CPU时间。
& & & &&在列表有更新时直接将原有的列表复制一份,并再新的列表上进行更新操作,完成后再将引用移到新的列表上。旧列表如果仍在使用中(比如遍历)则继续有效。如此一来就不会出现修改了正在使用的对象的情况(读和写分别发生在两个对象上),同时读操作也不必等待写操作的完成,免去了锁的使用加快了读取速度。
3.3&Collections.synchronizedList & CopyOnWriteArrayList在读写操作上的差距
& & & & 测试代码:
package com.yang.
import org.junit.T
import java.util.*;
import java.util.concurrent.*;
* Created with IntelliJ IDEA.
* User: yangzl2008
* Date: 14-9-18
* Time: 下午8:36
* To change this template use File | Settings | File Templates.
public class Test02 {
private int NUM = 10000;
private int THREAD_COUNT = 16;
public void testAdd() throws Exception {
List&Integer& list1 = new CopyOnWriteArrayList&Integer&();
List&Integer& list2 = Collections.synchronizedList(new ArrayList&Integer&());
Vector&Integer& v
= new Vector&Integer&();
CountDownLatch add_countDownLatch = new CountDownLatch(THREAD_COUNT);
ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
int add_copyCostTime = 0;
int add_synchCostTime = 0;
for (int i = 0; i & THREAD_COUNT; i++) {
add_copyCostTime += executor.submit(new AddTestTask(list1, add_countDownLatch)).get();
System.out.println(&CopyOnWriteArrayList add method cost time is & + add_copyCostTime);
for (int i = 0; i & THREAD_COUNT; i++) {
add_synchCostTime += executor.submit(new AddTestTask(list2, add_countDownLatch)).get();
System.out.println(&Collections.synchronizedList add method cost time is & + add_synchCostTime);
public void testGet() throws Exception {
List&Integer& list = initList();
List&Integer& list1 = new CopyOnWriteArrayList&Integer&(list);
List&Integer& list2 = Collections.synchronizedList(list);
int get_copyCostTime = 0;
int get_synchCostTime = 0;
ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
CountDownLatch get_countDownLatch = new CountDownLatch(THREAD_COUNT);
for (int i = 0; i & THREAD_COUNT; i++) {
get_copyCostTime += executor.submit(new GetTestTask(list1, get_countDownLatch)).get();
System.out.println(&CopyOnWriteArrayList add method cost time is & + get_copyCostTime);
for (int i = 0; i & THREAD_COUNT; i++) {
get_synchCostTime += executor.submit(new GetTestTask(list2, get_countDownLatch)).get();
System.out.println(&Collections.synchronizedList add method cost time is & + get_synchCostTime);
private List&Integer& initList() {
List&Integer& list = new ArrayList&Integer&();
int num = new Random().nextInt(1000);
for (int i = 0; i & NUM; i++) {
list.add(num);
class AddTestTask implements Callable&Integer& {
List&Integer&
CountDownLatch countDownL
AddTestTask(List&Integer& list, CountDownLatch countDownLatch) {
this.list =
this.countDownLatch = countDownL
public Integer call() throws Exception {
int num = new Random().nextInt(1000);
long start = System.currentTimeMillis();
for (int i = 0; i & NUM; i++) {
list.add(num);
long end = System.currentTimeMillis();
countDownLatch.countDown();
return (int) (end - start);
class GetTestTask implements Callable&Integer& {
List&Integer&
CountDownLatch countDownL
GetTestTask(List&Integer& list, CountDownLatch countDownLatch) {
this.list =
this.countDownLatch = countDownL
public Integer call() throws Exception {
int pos = new Random().nextInt(NUM);
long start = System.currentTimeMillis();
for (int i = 0; i & NUM; i++) {
list.get(pos);
long end = System.currentTimeMillis();
countDownLatch.countDown();
return (int) (end - start);
操作结果:
CopyOnWriteArrayList
&Collections.
synchronizedList
CopyOnWriteArrayList
&Collections.
synchronizedList
& & & & 写操作:在线程数目增加时CopyOnWriteArrayList的写操作性能下降非常严重,而Collections.synchronizedList虽然有性能的降低,但下降并不明显。
& & & & 读操作:在多线程进行读时,Collections.synchronizedList和CopyOnWriteArrayList均有性能的降低,但是Collections.synchronizedList的性能降低更加显著。
& & & &&CopyOnWriteArrayList,发生修改时候做copy,新老版本分离,保证读的高性能,适用于以读为主,读操作远远大于写操作的场景中使用,比如缓存。而Collections.synchronizedList则可以用在CopyOnWriteArrayList不适用,但是有需要同步列表的地方,读写操作都比较均匀的地方。
本文已收录于以下专栏:
相关文章推荐
列表实现有ArrayList、Vector、CopyOnWriteArrayList、Collections.synchronizedList(list)四种方式。
1 ArrayList
今天看java并发编程时,发现一段有趣的代码。顺便记记笔记。
@NotThreadSafe
class BadListHelper
public List list = Colle...
Collections.synchronizedList 工厂方法
通常的Map,Set,List实现都不是线程安全的,通过这些工厂方法可以得到相应的同步容器,相当于增强了访问控制,把一个链表对象...
来源:http://my.oschina.net/u/876257/blog/175470
有些容器是线程安全的,比如:Vector, 而有些是不安全的,如:List。Collections...
1 :关注要点,为什么在有synchroniezed方法的同时会出现 Collections.synchronizedList
2 :知识背景: 您可能需要了解java Synchronize...
在项目开发中,有时会遇到与SSL安全证书导入打交道的,如何把证书导入java中的cacerts证书库呢?
其实很简单,方法如下:
每一步:进入某个开头的网站,...
Openfire使用上的一些技巧作者:chszs,版权所有,未经同意,不得转载。博主主页:http://blog.csdn.net/chszs1、把Openfire安装为系统服务对于RedHat、Ce...
CopyOnWriteArrayList:专为多线程并发设计的容器,“写入时复制”策略。
Collections.synchronizedMap:同步容器,独占策略。
代码:
...
CopyOnWriteArrayList与Collections.synchronizedList的性能对比
列表实现有ArrayList、Vector、CopyOnWriteArray...
2、线程安全实现
他的最新文章
讲师:董岩
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)Collections.synchronizedList 工厂方法 - CSDN博客
Collections.synchronizedList 工厂方法
&Collections.synchronizedList 工厂方法
通常的Map,Set,List实现都不是线程安全的,通过这些工厂方法可以得到相应的同步容器,相当于增强了访问控制,把一个链表对象传递过来后,我们都通过返回的这个链表对象来进行各种操作(都是同步方法),而不再操纵底层的那个链表。此外,在Vector和同步封装器类中是用内置锁来来支持客户端加锁,所以我们可以进行扩展。
在对对链表迭代的过程中也要注意加锁,否则在迭代的过程中,如果其他某个线程改变了容器的属性,next,hasNext方法就会抛出ConcurrentModificationException
异常(而诸如ConcurrentHashMap的并发容器不需要迭代过程加锁)。更重要的是,要防止隐藏迭代,如果对某个容器调用toString方法的时候。下面是对应的代码。
1.迭代的时候要同步。
List&Integer& safeList =&Collections.&synchronizedList(&new&ArrayList&Integer&());
&&&&&&synchronized&(safeList)
&&&&&&&&&& Iterator&Integer& i = safeList.iterator();&// Must be in synchronized block
&&&&&&&&&&&while&(i.hasNext())
&&&&&&&&&&&&&& System.&out.println(i.next());
2.隐藏迭代器。
public&class&HiddenIterator
&&&&private&final&Set&Integer&&set&=&new&HashSet&Integer&();
&&&&public&synchronized&void&add(Integer
&&&&&&&&set.add(i);
&&&&public&synchronized&void&remove(Integer
&&&&&&&&set.remove(i);
&&&&public&void&addTenThings()
&&&&&&& Random r =&new&Random();
&&&&&&&&for&(&int&i
= 0; i & 10; i&#43;&#43;)
&&&&&&&&&&& add(r.nextInt());
&&&&&&& System.&out.println(&&DEBUG:
added ten elements to &&&#43;&set);&//这里
2.容器中toString方法的实现。
public&String toString() {
&&&&&&& Iterator&E& it = iterator();
&&&&&&&&if&(!
it.hasNext())
&&&&&&&&&&&&return&&[]&;
&&&&&&& StringBuilder sb =&new&StringBuilder();
&&&&&&& sb.append(&'[');
&&&&&&&&for&(;;)
&&&&&&&&&&& E e = it.next();
&&&&&&&&&&& sb.append(e ==&this&?&&(this
Collection)&&: e);
&&&&&&&&&&&&if&(!
it.hasNext())
&&&&&&&&&&&&&&&&return&sb.append(&']').toString();
&&&&&&&&&&& sb.append(&',').append(&'
本文已收录于以下专栏:
相关文章推荐
列表实现有ArrayList、Vector、CopyOnWriteArrayList、Collections.synchronizedList(list)四种方式。
1 ArrayList
列表实现有ArrayList、Vector、CopyOnWriteArrayList、Collections.synchronizedList(list)四种方式,其中...
今天看java并发编程时,发现一段有趣的代码。顺便记记笔记。
@NotThreadSafe
class BadListHelper
public List list = Colle...
来源:http://my.oschina.net/u/876257/blog/175470
有些容器是线程安全的,比如:Vector, 而有些是不安全的,如:List。Collections...
java中Collections.synchronized()的方法很好
有一次看到一个很优秀的同事写了以下一串代码,如下
private static volatile ConcurrentMap>...
final List list = Collections.synchronizedList(new ArrayList());
上边方法返回一个线程同步的list对象,即 :
当有一个线程获取到...
synchronizedList修饰list如下:
private static List TEST_LIST = Collections.synchronizedList(new ArrayLis...
Collections.synchronizedList引发的线程安全问题
有些容器是线程安全的(Vector,ConcurrentLinkedQueue等),有些则不是(list等)...
一直以为是
赋值过以后就全部remove了,
现在在做一个即时通讯,要发送语音。大家规定好的是aac文件。
现在是我这边录的发给IOS那边可以播放,我自己录的传到服务器再下载下来自己也可以播放,但是IOS那边录的我down下来之后就不行了。...
他的最新文章
讲师:董岩
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 线程同步synchronized 的文章

 

随机推荐