`

Collections.synchronizedList【转】

 
阅读更多

首先研究下Collection下的同步和非同步,例如ArrayList

 

    List 接口的大小可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。(此类大致上等同于 Vector 类,除了此类是不同步的。)sizeisEmptygetsetiteratorlistIterator 操作都以固定时间运行。add 操作以分摊的固定时间 运行,也就是说,添加 n 个元素需要 O(n) 时间。其他所有操作都以线性时间运行(大体上讲)。与用于 LinkedList 实现的常数因子相比,此实现的常数因子较低。每个 ArrayList 实例都有一个容量。该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向 ArrayList 中不断添加元素,其容量也自动增长。并未指定增长策略的细节,因为这不只是添加元素会带来分摊固定时间开销那样简单。在添加大量元素前,应用程序可以使用 ensureCapacity 操作来增加 ArrayList 实例的容量。这可以减少递增式再分配的数量。

 

       注意,此实现不是同步的。

 

       如果多个线程同时访问一个 ArrayList 实例,而其中至少一个线程从结构上修改了列表,那么它必须 保持外部同步。(结构上的修改是指任何添加或删除一个或多个元素的操作,或者显式调整底层数组的大小;仅仅设置元素的值不是结构上的修改。)这一般通过对自然封装该列表的对象进行同步操作来完成。如果不存在这样的对象,则应该使用 Collections.synchronizedList 方法将该列表“包装”起来。这最好在创建时完成,以防止意外对列表进行不同步的访问:

 

        List list = Collections.synchronizedList(new ArrayList(...)); 

 

此类的 iteratorlistIterator 方法返回的迭代器是快速失败的:在创建迭代器之后,除非通过迭代器自身的 removeadd 方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器都会抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。

 

注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器会尽最大努力抛出 ConcurrentModificationException。因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅用于检测 bug。

 

      如上所示,现在建立一个list集合,一个线程对集合进行写入操作,一个线程进行删除操作

 

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

public class MyArrayList {
	/**
	 * 创建一个列表,一个线程进行写入,一个线程读取 iterator 和 listIterator 方法返回的迭代器是快速失败的
	 */
	public void readWrite() {
		List<Integer> nums = new ArrayList<Integer>();
		
		List<Integer> synNums = Collections.synchronizedList(nums);
		
		//启动写入线程
		new WriteListThread(synNums).start();
		
		//启动删除线程
		new DeleteListThread(synNums).start();
	}

	public static void main(String[] args) {
		new MyArrayList().readWrite();
	}
}

class WriteListThread extends Thread {
	private List<Integer> nums;

	public WriteListThread(List<Integer> nums) {
		super("WriteListThread");
		this.nums = nums;
	}

	// 不停写入元素1
	public void run() {
		while (true) {
                    nums.add(new Random().nextInt(1000));	                                                                                                                                                System.out.println(Thread.currentThread().getName());
		
		}
	}
}

class DeleteListThread extends Thread {
	private List<Integer> nums;

	public DeleteListThread(List<Integer> nums) {
		super("DeleteListThread");
		this.nums = nums;
	}

	// 删除第一个元素
	public void run() {
		while (true) {
			try{
				System.out.println(Thread.currentThread().getName()+":"+nums.remove(0));
			}catch(Exception e){
				continue ;
			}
		}
	}
}

 通过List<Integer> synNums = Collections.synchronizedList(nums);就能对原子操作进行同步了,但是官方api示例为什么要自己手动添加同步呢?

 List list = Collections.synchronizedList(new ArrayList());
  synchronized(list) {
      Iterator i = list.iterator(); // Must be in synchronized block
      while (i.hasNext())
          foo(i.next());
  }

  查看Collections.synchronizedList的源代码

SynchronizedCollection(Collection<E> c) {
            if (c==null)
                throw new NullPointerException();
	    this.c = c;
            mutex = this;
}

 

public boolean add(E e) {
synchronized(mutex) {return c.add(e);}
        }
public boolean remove(Object o) {
	    synchronized(mutex) {return c.remove(o);}
        }

//没有进行同步操作
public Iterator<E> iterator() {
            return c.iterator(); // 由用户自己手动同步
        }

 可见对于集合同步操作,使用Collections的同步包装工具类,还需要对非原子操作用户还需要手动进行同步

如下所示,加一个线程,对集合进行读取

class ReadListThread extends Thread {
	private List<Integer> nums;

	public ReadListThread(List<Integer> nums) {
		super("ReadListThread");
		this.nums = nums;
	}

	// 不停读取元素,非原子操作,则需要手动加上锁
	public void run() {
		while (true) {
                        //休眠,将锁交给其他线程
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e1) {
				e1.printStackTrace();
			}
			synchronized (nums) {
				if (nums.size() > 100) {
					Iterator<Integer> iter = nums.iterator();
					while (iter.hasNext()) {
						System.out.println(Thread.currentThread().getName()
								+ ":" + iter.next());
						;
					}
				}else{
					try {
						nums.wait(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
}

 

 

 

 

 

分享到:
评论

相关推荐

    Collections.synchronizedList

    标题中的"Collections.synchronizedList"是指Java集合框架中的一个静态工厂方法,用于将任何List转换为线程安全的List。这个方法是Java中实现多线程环境下的集合操作的重要工具,确保在并发访问时数据的一致性和完整...

    spring-data-mongodb-test:在Collections.synchronizedList或Collections.synchronizedSet上测试spring数据mongodb ConcurrentModificationException

    Spring数据mongodb测试 在Collections.synchronizedList或Collections.synchronizedSet上测试spring数据mongodb ConcurrentModificationException

    Java Collections.pdf

    - 使用`Collections.synchronizedList()`方法包装集合。 - 使用并发集合类(如`ConcurrentHashMap`, `CopyOnWriteArrayList`)。 #### 八、高级主题 - **泛型与类型安全**:使用泛型确保类型安全,避免运行时的`...

    吐血推荐17个提升开发效率的“轮子”.doc

    List integers = Collections.synchronizedList(list);//将 ArrayList 转换成线程安全集合 System.out.println(integers); 4. 返回空集合:Collections.emptyList() 方法可以返回空集合。 例如: private List fun...

    Java的线程安全与不安全集合.docx

    2. 使用`Collections.synchronizedList(new ArrayList)`: 这种方法通过装饰器模式,将传入的`ArrayList`包装成`synchronizedList`,对所有调用的方法添加了同步控制。这样在并发环境下,多个线程调用`add()`等方法时...

    javaclooections类.docx

    - `Collections.synchronizedList(List l)`: 创建同步列表。 - `Collections.synchronizedMap(Map m)`: 创建同步映射。 - `Collections.synchronizedSet(Set s)`: 创建同步集合。 - `Collections....

    java ArrayList和Vector的区别详解

    在实际开发中,如果对线程安全有需求,可以考虑使用Collections.synchronizedList()方法将ArrayList转换为线程安全的列表,或者使用CopyOnWriteArrayList,这是一个更适合并发读写场景的线程安全实现。而如果在单...

    java中SynchronizedList和Vector的区别详解

    - `SynchronizedList` 是 `java.util.Collections` 类的一个静态内部类。它不直接实现 `List` 接口,而是通过包装一个现有的 `List` 实例(例如 `ArrayList` 或 `LinkedList`),并为这个实例添加同步机制来提供...

    java collections design.pdf

    3. 包装器实现:如Collections工具类提供的不可变版本(如Collections.unmodifiableList()),以及同步集合(如Collections.synchronizedList())。 4. 抽象实现:如AbstractList、AbstractSet和AbstractMap,提供...

    Java多线程安全集合

    例如,`Collections.synchronizedList`和`Collections.synchronizedMap`。同步集合在每个方法上加锁,确保同一时间只有一个线程可以执行操作。虽然提供了基本的线程安全性,但它们不是高度优化的并发解决方案,因为...

    java提高篇(二一)-----ArrayList.pdf

    此外,ArrayList不是线程安全的,如果在多线程环境中使用,需要通过Collections.synchronizedList方法使ArrayList同步。 二、ArrayList源码分析 1. 底层实现:ArrayList的内部字段`elementData`是一个transient的...

    了解Collection 和 Collections

    5. **线程安全**:`Collections.synchronizedList(List&lt;T&gt; list)`可以将一个非同步的`List`转换为线程安全的。 6. **集合拷贝**:`Collections.copy(List&lt;T&gt; dest, List&lt;? extends T&gt; src)`可以将源列表中的元素...

    Java集合多线程安全.docx

    2. 使用`Collections.synchronizedList`:这个静态方法可以将给定的`ArrayList`转换为线程安全的列表。在内部,它通过在方法调用上添加`synchronized`关键字来实现同步。这提供了线程安全的访问,但仍然需要谨慎处理...

    javabiginteger源码-MultiThreadMode:多线程模式

    java.util.ArrayList非线程安全的类,可用Collections.synchronizedList()进行包装 List list = Collections.synchronizedList(new ArrayList()); CopyOnWriteArrayList线程安全的类,适用于读操作频繁的场景。 Gua

    10个Java经典的List面试题!.pdf

    因此,如果需要在多线程环境下使用List,应该选择Vector或使用Collections.synchronizedList()方法来将List转换为线程安全的集合。 3.List是有序的吗? 是的,List是有序的。List中元素的顺序是固定的,可以使用...

    [线程技术]排序对象

    通过 `Collections.synchronizedList()`,我们确保了在并发访问时列表操作的正确性。 3. **排序**:`Collections.sort(list);` 使用 `Collections` 类的静态方法 `sort()` 对线程安全的列表进行排序。这个方法会...

    集合工具类Collections的基本应用

    - `synchronizedList(List&lt;T&gt; list)`: 返回给定列表的线程安全版本,通过包装器类实现了线程同步。这样多线程环境下访问列表时就不会出现数据不一致的问题。 - `synchronizedSet(Set&lt;T&gt; set)`: 类似地,返回给定...

    关于 Java Collections API 您不知道的 5 件事,第 1 部分

    除了以上五点,还有一些实用的工具类,如`Collections.synchronizedList()`用于同步列表,`Collections.unmodifiableList()`创建只读列表,以及`Collections.reverse()`用于反转列表等。了解并善用这些特性,可以...

    ArrayList的学习821.docx

    为了在多线程环境下安全地使用ArrayList,可以借助`Collections.synchronizedList`方法将其包装成线程安全的列表。例如: ```java List, Object&gt;&gt; test = Collections.synchronizedList(new ArrayList, Object&gt;&gt;())...

Global site tag (gtag.js) - Google Analytics