집합 클래스가 안전하지 않은 Set

3329 단어

1. 안전하지 않은 Set


위 코드:
    public static void main(String[] args) throws Exception {

        Set set = new HashSet<>();

        for (int i = 0;i<30;i++){
            new Thread(()->{
                set.add(Thread.currentThread().getName());
                System.out.println(Thread.currentThread().getName()+"\t"+set);
            }).start();
        }
    }

//      :       set  ,         
java.util.ConcurrentModificationException
    at java.util.HashMap$HashIterator.nextNode(HashMap.java:1445)
    at java.util.HashMap$KeyIterator.next(HashMap.java:1469)
    at java.util.AbstractCollection.toString(AbstractCollection.java:461)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at juc.ContainerNotSafeDemo.lambda$main$0(ContainerNotSafeDemo.java:17)
    at java.lang.Thread.run(Thread.java:748)

2. 안전한 해결 방법


CopyOnWriteArraySet을 사용하여 해결
    public static void main(String[] args) throws Exception {

        Set set = new CopyOnWriteArraySet<>();//new HashSet<>();

        for (int i = 0;i<30;i++){
            new Thread(()->{
                set.add(Thread.currentThread().getName());
                System.out.println(Thread.currentThread().getName()+"\t"+set);
            }).start();
        }
    }

쓰기 시 복제 기술에 관해서는 이 블로그에 쓴 적이 있으니 더 이상 군말하지 마라.소스 코드를 자세히 살펴보십시오.
public class CopyOnWriteArraySet extends AbstractSet   
        implements java.io.Serializable {
    private static final long serialVersionUID = 5457747651344034263L;

    private final CopyOnWriteArrayList al;

    /**
     * Creates an empty set.
     */
    public CopyOnWriteArraySet() {            //      
        al = new CopyOnWriteArrayList();  //       CopyOnWriteArrayList
    }
    ....
}

3. HashSet에 대한 보충


해시셋의 밑바닥은 무엇입니까?원본 보기:
    /**
     * Constructs a new, empty set; the backing HashMap instance has
     * default initial capacity (16) and load factor (0.75).
     */
    public HashSet() {
        map = new HashMap<>();
    }

주석의 뜻: 빈 HashMap을 만듭니다. 초기 용량은 16이고 부하 인자는 0.75입니다.
HashSet이dd에 전달된 값은 다음과 같지 않습니다.
new HashSet<>().add("hello");

HashSet 밑바닥이 HashMap인 거 확실해???
이것은 무시되기 쉬운 부분입니다. HashSet의dd 방법 원본을 보십시오.
    /**
     * Adds the specified element to this set if it is not already present.
     *            ,         。
     * More formally, adds the specified element e to this set if
     * this set contains no element e2 such that
     * (e==null?e2==null:e.equals(e2)).
     * If this set already contains the element, the call leaves the set
     * unchanged and returns false
     *            ,         ,  false。
     * @param e element to be added to this set
     * @return true if this set did not already contain the specified
     * element
     */
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

보시다시피dd 방법은 사실 HashMap에 Key를 추가한 것입니다.value는 PRESENT입니다. 이것은 Object 형식의 상수입니다.맵의dd 방법을 사용합니다.

좋은 웹페이지 즐겨찾기