Fix race condition on command output streams copy

And add more preconditions to error out if the race condition happens.
This should fix the CI errors on linux.
diff --git a/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/Command.java b/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/Command.java
index 594fa39..6217ae0 100644
--- a/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/Command.java
+++ b/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/Command.java
@@ -64,11 +64,19 @@
     executed = true;
     ProcessBuilder builder = new ProcessBuilder(args);
     builder.directory(directory);
+    builder.redirectOutput(ProcessBuilder.Redirect.PIPE);
+    builder.redirectError(ProcessBuilder.Redirect.PIPE);
     Process process = builder.start();
-    copyStream(process.getErrorStream(), stderr);
+    Thread err = copyStream(process.getErrorStream(), stderr);
     // seriously? That's stdout, why is it called getInputStream???
-    copyStream(process.getInputStream(), stdout);
+    Thread out = copyStream(process.getInputStream(), stdout);
     int r = process.waitFor();
+    if (err != null) {
+      err.join();
+    }
+    if (out != null) {
+      out.join();
+    }
     synchronized (stderr) {
       stderr.close();
     }
@@ -78,24 +86,39 @@
     return r;
   }
 
-  // Launch a thread to copy all data from inputStream to outputStream
-  private static void copyStream(InputStream inputStream, OutputStream outputStream) {
-    if (outputStream != null) new Thread(new Runnable() {
-      @Override
-      public void run() {
-        byte[] buffer = new byte[4096];
-        int read;
-        try {
-          while ((read = inputStream.read(buffer)) > 0) {
-            synchronized (outputStream) {
-              outputStream.write(buffer, 0, read);
-            }
+  private static class CopyStreamRunnable implements Runnable {
+    private InputStream inputStream;
+    private OutputStream outputStream;
+
+    CopyStreamRunnable(InputStream inputStream, OutputStream outputStream) {
+      this.inputStream = inputStream;
+      this.outputStream = outputStream;
+    }
+
+    @Override
+    public void run() {
+      byte[] buffer = new byte[4096];
+      int read;
+      try {
+        while ((read = inputStream.read(buffer)) > 0) {
+          synchronized (outputStream) {
+            outputStream.write(buffer, 0, read);
           }
-        } catch (IOException ex) {
-          // we simply terminate the thread on exceptions
         }
+      } catch (IOException ex) {
+        // we simply terminate the thread on exceptions
       }
-    }).start();
+    }
+  }
+
+  // Launch a thread to copy all data from inputStream to outputStream
+  private static Thread copyStream(InputStream inputStream, OutputStream outputStream) {
+    if (outputStream != null) {
+      Thread t = new Thread(new CopyStreamRunnable(inputStream, outputStream), "CopyStream");
+      t.start();
+      return t;
+    }
+    return null;
   }
 
   /**
diff --git a/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/SelectOutputStream.java b/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/SelectOutputStream.java
index 8514d5e..2f7c56e 100644
--- a/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/SelectOutputStream.java
+++ b/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/SelectOutputStream.java
@@ -58,6 +58,7 @@
 
   @Override
   public void write(int b) throws IOException {
+    Preconditions.checkState(!closed, "Attempted to write on a closed stream");
     byte b0 = (byte) b;
     if (b0 == '\n') {
       select(true);
diff --git a/javatests/com/google/devtools/bazel/e4b/command/CommandTest.java b/javatests/com/google/devtools/bazel/e4b/command/CommandTest.java
index 247933c..426ac34 100644
--- a/javatests/com/google/devtools/bazel/e4b/command/CommandTest.java
+++ b/javatests/com/google/devtools/bazel/e4b/command/CommandTest.java
@@ -85,7 +85,7 @@
     assertThat(cmd.run()).isEqualTo(0);
     String stdoutStr = new String(stdout.toByteArray(), StandardCharsets.UTF_8).trim();
     String stderrStr = new String(stderr.toByteArray(), StandardCharsets.UTF_8).trim();
-    
+
     assertThat(stdoutStr).isEqualTo("a");
     assertThat(stderrStr).isEqualTo("b");
     assertThat(cmd.getSelectedErrorLines()).containsExactly("a");
@@ -140,6 +140,7 @@
     builder.addArguments("pwd");
     Command cmd = builder.build();
     assertThat(cmd.run()).isEqualTo(0);
+    assertThat(cmd.getSelectedErrorLines()).isEmpty();
     assertThat(cmd.getSelectedOutputLines()).containsExactly(folder.getRoot().getCanonicalPath());
   }
 }