标签:复制 string 读写分离 需要 his 产生 cti 而在 system
线程不安全集合:
线程安全集合:
package com.raicho.mianshi.mycollection; import java.util.ArrayList; import java.util.List; import java.util.UUID; /** * @author: Raicho * @Description: * @program: mianshi * @create: 2020-07-17 15:32 **/ public class ArrayListConcurrentDemo { public static void main(String[] args) { List<String> list = new ArrayList<>(); for (int i = 0; i < 30; ++i) { new Thread(() -> { list.add(UUID.randomUUID().randomUUID().toString().substring(0, 4)); System.out.println(list); }).start(); } } }
运行报错:
ArrayList是线程不安全的,add()方法并没有加锁(synchronized),多线程环境下会抛出ConcurrentModificationException
解决方案:
package com.raicho.mianshi.mycollection; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; /** * @author: Raicho * @Description: * @program: mianshi * @create: 2020-07-17 15:32 **/ public class ArrayListConcurrentDemo { public static void main(String[] args) { List<String> list = Collections.synchronizedList(new ArrayList<>()); for (int i = 0; i < 50; ++i) { new Thread(() -> { list.add(UUID.randomUUID().randomUUID().toString().substring(0, 4)); System.out.println(list); },String.valueOf(i)).start(); } } }
源码:
static <T> List<T> synchronizedList(List<T> list, Object mutex) { return (list instanceof RandomAccess ? new SynchronizedRandomAccessList<>(list, mutex) : new SynchronizedList<>(list, mutex)); } static class SynchronizedList<E> extends SynchronizedCollection<E> implements List<E> { private static final long serialVersionUID = -7754090372962971524L; final List<E> list; SynchronizedList(List<E> list) { super(list); this.list = list; } SynchronizedList(List<E> list, Object mutex) { super(list, mutex); this.list = list; } public boolean equals(Object o) { if (this == o) return true; synchronized (mutex) {return list.equals(o);} } public int hashCode() { synchronized (mutex) {return list.hashCode();} } 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 E remove(int index) { synchronized (mutex) {return list.remove(index);} } public int indexOf(Object o) { synchronized (mutex) {return list.indexOf(o);} } public int lastIndexOf(Object o) { synchronized (mutex) {return list.lastIndexOf(o);} } public boolean addAll(int index, Collection<? extends E> c) { synchronized (mutex) {return list.addAll(index, c);} } public ListIterator<E> listIterator() { return list.listIterator(); // Must be manually synched by user } public ListIterator<E> listIterator(int index) { return list.listIterator(index); // Must be manually synched by user } public List<E> subList(int fromIndex, int toIndex) { synchronized (mutex) { return new SynchronizedList<>(list.subList(fromIndex, toIndex), mutex); } } @Override public void replaceAll(UnaryOperator<E> operator) { synchronized (mutex) {list.replaceAll(operator);} } @Override public void sort(Comparator<? super E> c) { synchronized (mutex) {list.sort(c);} } private Object readResolve() { return (list instanceof RandomAccess ? new SynchronizedRandomAccessList<>(list) : this); } }
package com.raicho.mianshi.mycollection; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.concurrent.CopyOnWriteArrayList; /** * @author: Raicho * @Description: * @program: mianshi * @create: 2020-07-17 15:32 **/ public class ArrayListConcurrentDemo { public static void main(String[] args) { List<String> list = new CopyOnWriteArrayList<>(); for (int i = 0; i < 30; ++i) { new Thread(() -> { list.add(UUID.randomUUID().randomUUID().toString().substring(0, 4)); System.out.println(list); },String.valueOf(i)).start(); } } }
源码:
// CopyOnWriteArrayList.java public boolean add(E e) { // 写操作加锁 final ReentrantLock lock = this.lock; lock.lock(); try { // 原有容器复制一份 Object[] elements = getArray(); int len = elements.length; // 创建一个容器,将原来的数据复制到新容器中,并且还有一个位置空余 Object[] newElements = Arrays.copyOf(elements, len + 1); // 将新元素添加到空余位置 newElements[len] = e; // 将原来指向旧容器的引用指向新容器 setArray(newElements); return true; } finally { // 写操作完成,解锁 lock.unlock(); } } public E set(int index, E element) { // 更新操作类似 final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); E oldValue = get(elements, index); if (oldValue != element) { int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len); newElements[index] = element; setArray(newElements); } else { // Not quite a no-op; ensures volatile write semantics setArray(elements); } return oldValue; } finally { lock.unlock(); } } // 读操作不加锁 private E get(Object[] a, int index) { return (E) a[index]; }
在添加元素e完后,再调用setArray(newElements);函数重新赋值,之前指向原容器的引用更改指向当前新容器
HashSet底层就是一个HashMap,默认的HashSet是一个初始大小为16,负载因子为0.75的HashMap:
HashSet的多线程安全问题实际上就是HashMap的多线程安全问题:
package com.raicho.mianshi.mycollection; import java.util.HashSet; import java.util.Set; import java.util.UUID; /** * @author: Raicho * @Description: * @program: mianshi * @create: 2020-07-17 17:03 * * HashSet多线程不安全问题 * HashSet底层就是HashMap,因此这个案例也是HashMap多线程不安全问题的演示 */ public class HashSetThreadUnsafe { public static void main(String[] args) { Set<String> sets = new HashSet<>(); for (int i = 0; i < 100; ++i) { new Thread(() -> { sets.add(UUID.randomUUID().toString().substring(0, 4)); System.out.println(sets); },String.valueOf(i)).start(); } } }
解决方案:
public class CopyOnWriteArraySet<E> extends AbstractSet<E> implements java.io.Serializable { private static final long serialVersionUID = 5457747651344034263L; private final CopyOnWriteArrayList<E> al; /** * Creates an empty set. */ public CopyOnWriteArraySet() { // 构造器内部实例化了一个CopyOnWriteArrayList al = new CopyOnWriteArrayList<E>(); } // ... }
相比于HashSet,HashMap除了可以使用Collections集合类的synchronizedMap方法外,还可以使用juc包下ConcurrentHashMap类。
package com.raicho.mianshi.mycollection; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; /** * @author: Raicho * @Description: * @program: mianshi * @create: 2020-07-17 17:03 */ public class HashMapThreadUnsafe { public static void main(String[] args) { Map<String,String> map = new ConcurrentHashMap<>(); for (int i = 0; i < 100; ++i) { new Thread(() -> { map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0, 4)); System.out.println(map); },String.valueOf(i)).start(); } } }
标签:复制 string 读写分离 需要 his 产生 cti 而在 system
原文地址:https://www.cnblogs.com/lzhdonald/p/13332727.html