基础学习-04-集合类不安全问题

并发修改异常问题及解决
package cn.chen.demo.containernosafedemo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 
 * @ClassName:  ListDemo  
 * @Description: 集合类不安全问题:List
 * @author: chenlf 
 *
 */
public class ListDemo {

	public static void main(String[] args) {
		
		/*List<String> list = Arrays.asList("a","b","c");
		list.forEach(System.out::println);*/
		
		/*//ArrayList 不加锁的。并发性上升,但是牺牲了数据的一致性。
		List<String> list = new ArrayList<>();*/
		
		/*//1)Vector 是加了锁的。数据一致性可以保证,但是并发性下降了。
		List<String> list = new Vector<>();*/
		
		/*//2) Collections.synchronizedList(new ArrayList<>());
		List<String> list = Collections.synchronizedList(new ArrayList<>());
		*/
		//3) java.util.concurrent.CopyOnWriteArrayList.CopyOnWriteArrayList<>()
		List<String> list = new CopyOnWriteArrayList<>();
		
		for (int i = 1; i <= 30; i++) {
			new Thread(()->{
				list.add(UUID.randomUUID().toString().substring(0, 8));
				System.out.println(list);
			},String.valueOf(i)).start();
		}
	}
	//报错:java.util.ConcurrentModificationException
	
	/**
	 * 1.故障现象
	 * 		java.util.ConcurrentModificationException
	 * 
	 * 2.导致原因
	 * 		并发争抢修改导致。
	 * 		eg:1)买奶茶按号排队领取。正在领奶茶时,另外一个人跑过来拿,导致拿错了。
	 * 		   2)花名册签名,一个同学正在签名,另外一个同学过来抢夺,导致数据不一致异常。
	 * 
	 * 3.解决方案
	 * 		1) new Vector<>();
	 * 		2) Collections.synchronizedList(new ArrayList<>());
	 * 		3) new CopyOnWriteArrayList<>();
	 * 
	 * 4.优化建议(不犯相同的错误)
	 * 
	 */
}

/**
输出结果:
java.util.ConcurrentModificationException
*/
写时复制
/** CopyOnWrite容器:写时复制容器
* 往一个容器添加元素时,不直接往当前容器Object[] elements添加,
* 而是对当前容器Object[]进行了复制。
* 复制出一个比当前容器长度+1的新容器Object[] newElements,
* 然后再往新容器里添加元素。
* 添加完元素之后,将原容器的引用指向新的容器setArray(newElements)
* 好处:可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。
* 所以CopyOnWrite容器也是一种读写分离的思想。【读和写是不同的容器】
*/
//boolean java.util.concurrent.CopyOnWriteArrayList.add(E e)
public boolean add(E e) {
	final ReentrantLock lock = this.lock;
	//加锁
	lock.lock();
	try {
		//获取当前数组
		Object[] elements = getArray();
		//当前数组长度
		int len = elements.length;
		//copy当前数组,并在当前数组的基础上长度+1
		Object[] newElements = Arrays.copyOf(elements, len + 1);
		//将新元素设置在新数组数组的最后,即索引为len
		newElements[len] = e;
		//将新数组再重新set回去
		setArray(newElements);
		return true;
	} finally {
		//释放锁
		lock.unlock();
	}
}
set
package cn.chen.demo.containernosafedemo;

import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * 
 * @ClassName:  SetDemo   
 * @Description: 集合类不安全问题Set
 * @author: chenlf 
 *
 */
public class SetDemo {
	public static void main(String[] args) {
		
		Set<String> set = new CopyOnWriteArraySet<>();
		/**
		 * 底层是一个CopyOnWriteArrayList
		 * public CopyOnWriteArraySet() {
		 * 		al = new CopyOnWriteArrayList<E>();
		 * }
		 */
		
		for (int i = 1; i <= 30; i++) {
			new Thread(()->{
				set.add(UUID.randomUUID().toString().substring(0, 8));
				System.out.println(set);
			},String.valueOf(i)).start();
		}
		
		new HashSet<>();//底层是hashMap
		/**
			hashMap是键值对,key-value,需要两个。
			但是hashSet.add(E e) ,只需要一个。
			原因看源码:
			 	public boolean add(E e) {
			        return map.put(e, PRESENT)==null;
			    }
			 由此可看出:e对应的就是map的key
			 另外:PRESENT 则是一个Object类型的常量(final修饰的)
		 */
		
	}
}

Map
package cn.chen.demo.containernosafedemo;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
 * 
 * @ClassName:  MapDemo   
 * @Description: 集合类安全问题Map
 * @author: chenlf 
 *
 */
public class MapDemo {
	public static void main(String[] args) {
		/*//1) new ConcurrentHashMap<>();
		Map<String, String> map = new ConcurrentHashMap<>();*/
		//2) Collections.synchronizedMap(new HashMap<>());
		Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
		for (int i = 1; i <= 30; i++) {
			new Thread(()->{
				map.put(Thread.currentThread().getName()
							,UUID.randomUUID().toString().substring(0, 8));
				System.out.println(map);
			},String.valueOf(i)).start();
		}
	}
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值