--- old/src/java.base/share/classes/java/lang/ProcessBuilder.java 2019-07-19 13:42:21.926172540 -0700 +++ new/src/java.base/share/classes/java/lang/ProcessBuilder.java 2019-07-19 13:42:21.490172431 -0700 @@ -25,6 +25,8 @@ package java.lang; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; import java.io.File; import java.io.FileDescriptor; import java.io.IOException; @@ -209,7 +211,7 @@ public ProcessBuilder(List command) { if (command == null) throw new NullPointerException(); - this.command = command; + COMMAND.setRelease(this, command); } /** @@ -224,9 +226,10 @@ * @param command a string array containing the program and its arguments */ public ProcessBuilder(String... command) { - this.command = new ArrayList<>(command.length); + List commandList = new ArrayList<>(command.length); for (String arg : command) - this.command.add(arg); + commandList.add(arg); + COMMAND.setRelease(this, commandList); } /** @@ -243,7 +246,7 @@ public ProcessBuilder command(List command) { if (command == null) throw new NullPointerException(); - this.command = command; + COMMAND.setRelease(this, command); return this; } @@ -274,7 +277,7 @@ * @return this process builder's program and its arguments */ public List command() { - return command; + return (List) COMMAND.getAcquire(this); } /** @@ -350,12 +353,15 @@ if (security != null) security.checkPermission(new RuntimePermission("getenv.*")); - if (environment == null) - environment = ProcessEnvironment.environment(); - - assert environment != null; - - return environment; + // Multiple threads may call this method without synchronization + for (;;) { + Map environment = (Map) + ENVIRONMENT.getAcquire(this); + if (environment != null) + return environment; + ENVIRONMENT.compareAndSet(this, null, + ProcessEnvironment.environment()); + } } // Only for use by Runtime.exec(...envp...) @@ -1298,4 +1304,19 @@ } return processes; } + + // VarHandle mechanics + private static final VarHandle COMMAND; + private static final VarHandle ENVIRONMENT; + static { + try { + MethodHandles.Lookup l = MethodHandles.lookup(); + COMMAND = l.findVarHandle( + ProcessBuilder.class, "command", List.class); + ENVIRONMENT = l.findVarHandle( + ProcessBuilder.class, "environment", Map.class); + } catch (ReflectiveOperationException e) { + throw new ExceptionInInitializerError(e); + } + } }