jdk5的线程安全集合

package com.thread_test;


import java.util.ArrayList;
import java.util.Iterator;

/**
 * Created by zhen on 2017-06-09.
 */
public class SynchronizedCollectionTest {
    /**
     * 传统线程在并发访问时的问题

     hashMap是线程不安全的.可以使用hashMap时加上同步解决。
     jdk1.5之前的解决方法是使用Collections.synchronizedMap()方法得到同步的Map。

     这个是怎么实现的呢?可以看看源码:
     返回一个synchronizedMap对象,观察synchronizedMap类:
     private static class SynchronizedMap<K,V>
     implements Map<K,V>, Serializable {
     private static final long serialVersionUID = 1978198479659022715L;

     private final Map<K,V> m;     // Backing Map
     final Object      mutex;        // Object on which to synchronize

     SynchronizedMap(Map<K,V> m) {
     this.m = Objects.requireNonNull(m);
     mutex = this;
     }

     SynchronizedMap(Map<K,V> m, Object mutex) {
     this.m = m;
     this.mutex = mutex;
     }

     public int size() {
     synchronized (mutex) {return m.size();}
     }
     public boolean isEmpty() {
     synchronized (mutex) {return m.isEmpty();}
     }
     public boolean containsKey(Object key) {
     synchronized (mutex) {return m.containsKey(key);}
     }
     public boolean containsValue(Object value) {
     synchronized (mutex) {return m.containsValue(value);}
     }
     public V get(Object key) {
     synchronized (mutex) {return m.get(key);}
     }

     public V put(K key, V value) {
     synchronized (mutex) {return m.put(key, value);}
     }
     public V remove(Object key) {
     synchronized (mutex) {return m.remove(key);}
     }
     public void putAll(Map<? extends K, ? extends V> map) {
     synchronized (mutex) {m.putAll(map);}
     }
     public void clear() {
     synchronized (mutex) {m.clear();}
     }

     private transient Set<K> keySet;
     private transient Set<Map.Entry<K,V>> entrySet;
     private transient Collection<V> values;

     public Set<K> keySet() {
     synchronized (mutex) {
     if (keySet==null)
     keySet = new SynchronizedSet<>(m.keySet(), mutex);
     return keySet;
     }
     }
     。。。
     这尼玛,代理。有点装饰模式的样子,是你,有你增强你。

     在并发状态,可以使用concurrentHashMap替代hashMap。concurrentSkipListMap是可以排序的安全map,类似treeMap

     我们的ArrayList等简单几何还有一些问题,比如在遍历的时候删除:
        当下面的元素删除1的时候抛出异常:版本修改异常
        删除2的时候却没有问题
        删除3的时候抛出版本修改异常
     这是为什么呢?

     我们查看源码:
     public boolean hasNext() {
         return cursor != size;
     }
     public E next() {
         checkForComodification();
         int i = cursor;
         if (i >= size)
         throw new NoSuchElementException();
         Object[] elementData = ArrayList.this.elementData;
         if (i >= elementData.length)
         throw new ConcurrentModificationException();
         cursor = i + 1;
         return (E) elementData[lastRet = i];
     }
     final void checkForComodification() {
         if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
     }
     modCount != expectedModCount;
     查看代码:
        刚开始 int expectedModCount = modCount;
        进行集合元素的修改的时候,会将modCount++
     然后在next()方法中调用进行判断,这个版本有点事乐观锁的概念,我隐约听过这个概念。

     就是在next()方法内抛出的异常。所以1,和3的删除都抛出了版本修改异常。
     为什么删除2的时候不抛异常呢?
        因为在next()之前我们调用了hasNext()方法,它比较cursor和size。如果相等则返回false,否则返回true。2的时候刚好集合的大小与指针的位置大小相等,所以不往下走了。
     删除3的时候cousor与size永远不可能相等了,所以hasNext永远返回true。好在next()方法中有检查版本,所以抛出了异常

     jdk5的线程安全类不仅解决了安全问题,将这个问题也一并解决了。
     CopyOnWriteArrayList 和 CopyOnWriteArraySet 可以替换我们常用的ArrayList和HashSet。
     如果Set要排序使用ConcurrentSkipListSet
     
     hashSet本身是内置一个hashMap,就是一个hashMap的key的集合。



     */

    public static void main(String[] args){
        ArrayList<String> users = new ArrayList<String>();
        users.add("1");
        users.add("2");
        users.add("3");
        Iterator<String> iterator = users.iterator();
        while(iterator.hasNext()){
            String obj = iterator.next();
            if(obj.equals("1")){
                users.remove(obj);
            }else{
                System.out.println(obj);
            }

        }
    }

}

 

posted @ 2017-06-09 18:32  guodaxia  阅读(165)  评论(0)    收藏  举报