HashMap i widoczność

Jashadoc HashMap stwierdza:

jeśli mapa zostanie zmodyfikowana strukturalnie w dowolnym momencie po utworzeniu iteratora, w dowolny sposób, za wyjątkiem własnej metody usuwania iteratora, iterator wyśle ​​wyjątek ConcurrentModificationException.

Zbudowałem przykładowy kod, który w oparciu o specyfikację ma niemal natychmiastowo zawieść i wywołać wyjątek ConcurrentModificationException;

Od razu kończy się niepowodzeniem zgodnie z oczekiwaniami w Java 7ale (wydaje się) zawsze działa z Javą 6 (tzn. nie rzuca obiecanego wyjątku).

Uwaga: czasami nie zawodzi w Javie 7 (powiedzmy 1 raz na 20) - myślę, że ma to związek z planowaniem wątków (tzn. 2 runnables nie są przeplatane).

Czy czegoś mi brakuje? Dlaczego wersja działa z Java 6 nie rzuca wyjątku ConcurrentModificationException?

Zasadniczo istnieją 2 zadania Runnable uruchomione równolegle (funkcja countdownlatch służy do ich rozpoczęcia w przybliżeniu w tym samym czasie):

jeden to dodawanie elementów do mapydrugi to iteracja po mapie, czytanie kluczy i umieszczanie ich w tablicy

Główny wątek sprawdza następnie, ile kluczy zostało dodanych do tablicy.

Typowe wyjście Java 7 (iteracja nie powiedzie się natychmiast):

java.util.ConcurrentModificationException
MAX i = 0

Typowe wyjście Java 6 (cała iteracja przechodzi, a tablica zawiera wszystkie dodane klucze):

MAX i = 99

Użyty kod:

public class Test1 {

    public static void main(String[] args) throws InterruptedException {
        final int SIZE = 100;
        final Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        map.put(1, 1);
        map.put(2, 2);
        map.put(3, 3);
        final int[] list = new int[SIZE];
        final CountDownLatch start = new CountDownLatch(1);
        Runnable put = new Runnable() {
            @Override
            public void run() {
                try {
                    start.await();
                    for (int i = 4; i < SIZE; i++) {
                        map.put(i, i);
                    }
                } catch (Exception ex) {
                }
            }
        };

        Runnable iterate = new Runnable() {
            @Override
            public void run() {
                try {
                    start.await();
                    int i = 0;
                    for (Map.Entry<Integer, Integer> e : map.entrySet()) {
                        list[i++] = e.getKey();
                        Thread.sleep(1);
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        };
        ExecutorService e = Executors.newFixedThreadPool(2);
        e.submit(put);
        e.submit(iterate);
        e.shutdown();

        start.countDown();
        Thread.sleep(100);
        for (int i = 0; i < SIZE; i++) {
            if (list[i] == 0) {
                System.out.println("MAX i = " + i);
                break;
            }
        }
    }
}

Uwaga: używanie JDK 7u11 i JDK 6u38 (wersja 64-bitowa) na komputerze x86.

questionAnswers(3)

yourAnswerToTheQuestion