java基础之集合框架——Collection1-同步和非同步

首先研究下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();
					}
				}
			}
		}
	}
}
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 集合中添加元素可以使用 add() 方法。 例如: ```java List<String> list = new ArrayList<String>(); list.add("item1"); list.add("item2"); ``` 也可以使用 addAll() 方法将一个集合中的所有元素添加到另一个集合中。 例如: ```java List<String> list1 = new ArrayList<String>(); list1.add("item1"); list1.add("item2"); List<String> list2 = new ArrayList<String>(); list2.add("item3"); list2.add("item4"); list1.addAll(list2); ``` 这样,list1 中就包含了 "item1","item2","item3" 和 "item4"。 ### 回答2: Java集合类是Java编程语言中最重要的数据结构之一。它们提供了一种方便、快速和高效地管理数据的方法。集合类的主要作用就是存储和操作数据,Java集合类的一个关键接口就是Collection接口。在Java中,Collection接口是所有集合类的根接口,因此,学习使用Collection接口是理解和使用Java集合类的基础。 往集合中添加元素是Collection接口的基本操作之一。在Java中,我们可以使用add()方法将元素添加到集合中。add()方法是Collection接口中的一个标准方法,它用于将一个元素添加到集合中。在使用add()方法时,我们只需要将要添加的元素传递给这个方法即可。例如: ```Java ArrayList<String> list = new ArrayList<>(); list.add("Java"); list.add("Python"); list.add("PHP"); ``` 在这个例子中,我们使用ArrayList集合类初始化了一个list对象,然后使用add()方法向集合中添加了三个元素,分别是”Java”,”Python”和”PHP”。 除了add()方法之外,Collection接口还提供了许多其他的方法用于向集合中添加元素,如addAll()、offer()和push()等。这些方法都可以实现向集合中添加元素的功能,具体选择哪个方法,取决于具体的需求。例如,addAll()方法可以添加一个集合中的所有元素,而push()方法只能添加一个元素到栈顶。 总的来说,学习Java集合类中Collection接口中添加元素的方法很重要,它是理解Java集合类的基础之一。掌握添加元素的各种方法,可以让我们更加高效地管理和操作Java集合中的数据。 ### 回答3: Java集合类是Java开发中常常用的数据类型,而往集合中添加元素是其基本操作之一。其中,Collection接口是Java集合类中最基本的接口,所有的集合类都可以通过实现该接口来实现元素的添加、删除、查找等操作。 往一个集合中添加元素,通常可以用add()方法来完成。在Collection接口中,add()方法用于向集合中添加一个元素。例如,我们可以使用以下代码向一个List类型的集合中添加一个元素: ```java List<String> list = new ArrayList<String>(); list.add("Java"); ``` 上述代码中,我们创建了一个ArrayList类型的list集合,并使用add()方法向其中添加了一个字符串元素"Java"。 需要注意的是,在使用add()方法时,需要注意元素类型的匹配。例如,如果我们创建的集合类型为List<Integer>,则不能添加其他类型的元素,否则会编译错误。 此外,Collection接口中还提供了addAll()方法,用于将一个集合中的所有元素批量添加到另一个集合中。例如,我们可以使用以下代码将一个数组中的所有元素添加到一个Set类型的集合中: ```java Set<Integer> set = new HashSet<Integer>(); Integer[] arr = new Integer[]{1, 2, 3, 4}; set.addAll(Arrays.asList(arr)); ``` 上述代码中,我们首先创建了一个HashSet类型的set集合,然后使用addAll()方法将数组arr中所有的元素添加到set集合中。 除了使用add()和addAll()方法往集合中添加元素外,Java集合类还提供了其他方法用于添加、删除、查找元素,如remove()、contains()等。不同类型的集合类有着不同的实现方法,开发者可以根据具体需求选择合适的集合类型和操作方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值