java集合框架线程同步代码详解

 更新时间:2017年12月22日 08:39:00   作者:光与热  
这篇文章主要介绍了java集合框架线程同步代码详解,具有一定借鉴价值,需要的朋友可以参考下。

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

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

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

Listlist=Collections.synchronizedList(newArrayList(...));

此类的iterator和listIterator方法返回的迭代器是快速失败的:在创建迭代器之后,除非通过迭代器自身的remove或add方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器都会抛出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; 
    } 
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 ;
			}
		}
	}
}

可见对于集合同步操作,使用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();
					}
				}
			}
		}
	}
}

总结

以上就是本文关于java集合框架线程同步代码详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

相关文章

  • Springboot Thymeleaf实现HTML属性设置

    Springboot Thymeleaf实现HTML属性设置

    这篇文章主要介绍了Springboot Thymeleaf实现HTML属性设置,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2007-11-11
  • SpringBoot中OKHttp和压缩文件的使用实战教程

    SpringBoot中OKHttp和压缩文件的使用实战教程

    本文介绍了如何在SpringBoot中使用OKHttp发起请求和处理压缩文件,包括文件的存储配置、实体类、配置类和初始化类的设置,以及如何通过主程序和测试类进行实际操作,最后提供了必要的依赖添加方法,以确保功能的实现
    2024-10-10
  • myeclipse导出可运行jar包简介

    myeclipse导出可运行jar包简介

    这篇文章主要介绍了myeclipse导出可运行jar包简介,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • Java8函数式编程应用小结

    Java8函数式编程应用小结

    Java8非常重要的就是引入了函数式编程的思想,使得这门经典的面向对象语言有了函数式的编程方式,弥补了很大程度上的不足,函数式思想在处理复杂问题上有着更为令人称赞的特性,本文给大家介绍Java8函数式编程应用小结,感兴趣的朋友一起看看吧
    2023-12-12
  • 详解Java设计模式之桥接模式

    详解Java设计模式之桥接模式

    桥接,顾名思义,就是用来连接两个部分,使得两个部分可以互相通讯。桥接模式将系统的抽象部分与实现部分分离解耦,使他们可以独立的变化。本文通过示例详细介绍了桥接模式的原理与使用,需要的可以参考一下
    2022-06-06
  • spring解决循环依赖的简单方法

    spring解决循环依赖的简单方法

    这篇文章主要给大家介绍了关于spring解决循环依赖的简单方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • Java实现输入流转化为String

    Java实现输入流转化为String

    这篇文章主要介绍了Java实现输入流转化为String的相关资料,需要的朋友可以参考下
    2016-12-12
  • springmvc的@Validated注解使用

    springmvc的@Validated注解使用

    这篇文章主要介绍了springmvc的@Validated注解使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • elasticsearch节点的transport请求发送处理分析

    elasticsearch节点的transport请求发送处理分析

    这篇文章主要为大家介绍了elasticsearch节点的transport请求发送处理分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-04-04
  • Maven使用Nexus创建私服的实现

    Maven使用Nexus创建私服的实现

    本文主要介绍了Maven使用Nexus创建私服的实现,通过建立自己的私服,就可以降低中央仓库负荷、节省外网带宽、加速Maven构建、自己部署构件等,从而高效地使用Maven,感兴趣的可以了解一下
    2024-04-04

最新评论