¿Cómo se comportan las secuencias paralelas de Java 8 en una excepción lanzada?

¿Cómo se comportan las secuencias paralelas de Java 8 en una excepción lanzada en la cláusula de consumo, por ejemplo enforEach ¿manejo? Por ejemplo, el siguiente código:

final AtomicBoolean throwException = new AtomicBoolean(true);
IntStream.range(0, 1000)
    .parallel()
    .forEach(i -> {
        // Throw only on one of the threads.
        if (throwException.compareAndSet(true, false)) {
            throw new RuntimeException("One of the tasks threw an exception. Index: " + i);
        });

¿Detiene los elementos manejados inmediatamente? ¿Espera a que finalicen los elementos ya iniciados? ¿Espera a que termine toda la transmisión? ¿Comienza a manejar elementos de flujo después de que se lanza la excepción?

¿Cuándo vuelve? Inmediatamente después de la excepción? ¿Después de que todos / parte de los elementos fueron manejados por el consumidor?

¿Los elementos continúan siendo manejados después de que la secuencia paralela arrojó la excepción? (Encontró un caso donde esto sucedió).

¿Hay una regla general aquí?

EDITAR (15-11-2016)

Intentando determinar si la secuencia paralela regresa temprano, descubrí que no está determinada:

@Test
public void testParallelStreamWithException() {
    AtomicInteger overallCount = new AtomicInteger(0);
    AtomicInteger afterExceptionCount = new AtomicInteger(0);
    AtomicBoolean throwException = new AtomicBoolean(true);

    try {
        IntStream.range(0, 1000)
            .parallel()
            .forEach(i -> {
                overallCount.incrementAndGet();
                afterExceptionCount.incrementAndGet();
                try {
                    System.out.println(i + " Sleeping...");
                    Thread.sleep(1000);
                    System.out.println(i + " After Sleeping.");
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // Throw only on one of the threads and not on main thread.
                if (!Thread.currentThread().getName().equals("main") && throwException.compareAndSet(true, false)) {
                    System.out.println("Throwing exception - " + i);
                    throw new RuntimeException("One of the tasks threw an exception. Index: " + i);
                }
            });
        Assert.fail("Should not get here.");
    }
    catch (Exception e) {
        System.out.println("Cought Exception. Resetting the afterExceptionCount to zero - 0.");
        afterExceptionCount.set(0);
    }
    System.out.println("Overall count: " + overallCount.get());
    System.out.println("After exception count: " + afterExceptionCount.get());
}

Regreso tardío al tirar no desde el hilo principal. Esto causó muchonuevo elementos a ser manejados mucho después de que se lanzó la excepción. En mi máquina, se manejaron unos 200 elementos después de que se lanzó la excepción. PERO, no todos los 1000 elementos fueron manejados. Entonces, ¿cuál es la regla aquí? ¿Por qué se manejaron más elementos a pesar de que se lanzó la excepción?

Regreso temprano al eliminar el no (!), provocando que la excepción sea lanzada en el hilo principal. Solo los elementos ya iniciados finalizaron el procesamiento y no se manejaron nuevos. Regresar temprano fue el caso aquí. No es consistente con el comportamiento anterior.

¿Que me estoy perdiendo aqui?

Respuestas a la pregunta(1)

Su respuesta a la pregunta