0

I came across the following issue when using parallel lambdas.

I have a static initialisation block in a class which iterates over an array in parallel however, i noticed from the stack trace that the very first iteration completes correctly and computers, however all subsequent iterations block. (Thread dump states "Waiting for: ") which is really not helpful.

Here is the code that thread locks.

public static class Test {
    private static final Object[] objects;

    static {
        objects = new Object[9];
        IntStream.range(0, objects.length).parallel().forEach(i -> objects[i] = null);
    }
}

After some head scratching as to why setting an array index to null would cause a thread lock I came up with the following. I created a temporary array within the static block and then assigned the class array at the end which fixed the issue.

public static class Test {
    private static final Object[] objects;

    static {
        Object[] tempObjects = new Object[9];
        IntStream.range(0, tempObjects.length).parallel().forEach(i -> tempObjects[i] = null);
        objects = tempObjects;
    }
}

Does anyone have any insight as to why the first code block thread locks and the second code block does not?

Ele
  • 33,468
  • 7
  • 37
  • 75
BillF
  • 21
  • 1
  • 2
    I hope you're aware that just `objects = new Object[9];` does what you're trying to do with your parallel stream. Also, a parallel stream to do a trivial operation 9 times is completely overkill. parallel doesn't mean "magically faster". – JB Nizet Dec 28 '17 at 22:44
  • 2
    Why would you initialize it to null when all elements are null after you define the size ? – whatamidoingwithmylife Dec 28 '17 at 22:45
  • What do you mean "the first iteration completes correctly, subsequent operations block"? There's only one time this code gets called. – daniu Dec 28 '17 at 22:47
  • @GCP, I set them all null as an example, as posting the larger code would be irrelevant (this is the most barebones example with the issue I have come across). – BillF Dec 28 '17 at 22:50
  • @JBNizet, yes parallel for 9 objects is overkill, however 9 was just a random number i picked to show the issue. – BillF Dec 28 '17 at 22:54
  • @daniu the first iteration within the IntStream.range(start,end) executes but all others block – BillF Dec 28 '17 at 22:54

1 Answers1

4

When the class is being staticly initialized the JVM holds a class-level lock. The lock prevents other threads from accessing the class until it is fully initialized.

There is no need to do what you're trying to do, anyways. A new Object[9] array is already initialized to all nulls. Not to mention, even if it did work, parallelism has a ton of overhead. The overhead would vastly outweigh any benefit from splitting up this task across multiple cores. (With 9 elements there is no benefit.)

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 3
    More specifically, the class is locked, and inaccessible from other threads, so the lambda code, which runs is separate threads, cannot access the `objects` static field. The second version of the code only accesses the `objects` static field from the initializer block itself, which is why it works. *Conclusion:* **Do not runs threads from a static initializer.** – Andreas Dec 28 '17 at 22:52