Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-7147733

The 'for each' loop breaks thread scheduling in mixed mode for 1.5, 1.6 and 1.7

XMLWordPrintable

    • x86
    • windows_7

      FULL PRODUCT VERSION :
      java version "1.6.0_27"
      Java(TM) SE Runtime Environment (build 1.6.0_27-b07)
      Java HotSpot(TM) 64-Bit Server VM (build 20.2-b06, mixed mode)


      java version "1.7.0_03"
      Java(TM) SE Runtime Environment (build 1.7.0_03-b05)
      Java HotSpot(TM) 64-Bit Server VM (build 22.1-b02, mixed mode)

      java version "1.5.0_22"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_22-b03)
      Java HotSpot(TM) Client VM (build 1.5.0_22-b03, mixed mode, sharing)




      FULL OS VERSION :
      Microsoft Windows [Version 6.1.7601]

      EXTRA RELEVANT SYSTEM CONFIGURATION :
      Win7 amd64
      Intel Core 2 Quad Q9300


      A DESCRIPTION OF THE PROBLEM :
      There are two threads. Thread A performs number crunching and is MIN_PRIORITY, the other thread B sends keep-alives to stdout each 100ms and is MAX_PRIORITY.

      In a cold start VM in mixed mode if thread A uses 'for each' loop then it blocks thread B from sending keep-alives until thread A finishes or calls yield().

      If thread A uses ordinary 'for (int i ....)' loop instead of 'for each' loop everything seems to work fine.


      THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: No

      THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Yes

      REGRESSION. Last worked in version 1.4.2

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      The 'Source code for an executable test case' field contains the test case.

      There are two parameters:
       - slp - tells the test to wait before starting number crunching
       - iter - specifies amount of numbers to crunch

      Tests runs okay (no errors) on my machine if slp > 4000 or iter < 10000 (apprx.)
      Test fails (prints 'Test Failed') on my machine if slp < 3900 and iter > 20000 (apprx)

      In order to reproduce, run the test provided in 'Source code" field

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      It is expected that thread B would run in parallel with thread B as there are spare CPU cores.


      Expected when fails
      when slp < 3900 and iter > 30000 (apprx)
       test prints 'Test failed'
       prints stacktrace 'RuntimeException'
       there is an interval between consequent 'woken up...' longer than 200 ms (apprx 10 seconds on my machine)

      Expected when passes
      when slp > 4000 or iter < 10000 (apprx)
       test finishes without any errors
       all time intervals between consequent 'woken up...' are shorter than 1000 ms (usually about 100 ms)

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      VM did not crash. It exhibits incorrect behavior.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.text.SimpleDateFormat;
      import java.util.Calendar;
      import java.util.Random;

      class Calculator {
          private static Random rndGen = new Random();


      public void doCalc(int iter) {
      System.out.println("calculation started");

      long start = System.currentTimeMillis();
      Double[] portfolio = new Double[5000];

      Random rnd = new Random();

      for (int i = 0; i < portfolio.length; i++) {
      portfolio[i] = new Double(50000 * rnd.nextDouble());
      }
            
      double[] losses = new double[iter];

      for (int i = 0; i < iter; i++) {
      for (Double crd : portfolio) {
      if (rndGen.nextDouble() >= 1 - rndGen.nextDouble()) {
      losses[i] += 1 + Math.sqrt(crd);
      } else {
      losses[i] -= 1 + Math.sqrt(crd);
      }
      }
      }


      System.out.println("calculation finished in " + (System.currentTimeMillis() - start) + " ms");
      }
      }

      public class TestSleep {



      /**
      * @param args
      */
      public static void main(String[] args) throws InterruptedException {

      // change slp to >4000 for test to run ok
      int slp = Integer.parseInt(args[0]);

      // tune this parameter for computation to run more than 4000 ms
      int iter = Integer.parseInt(args[1]);


      Thread thread = new Thread( new Runnable() {
      SimpleDateFormat fmt = new SimpleDateFormat("kk:mm:ss.SSS");

      public void run() {
      while (true) {

      long time = System.currentTimeMillis();

      try {
      Thread.sleep(100);
       
      } catch (InterruptedException e) {
      e.printStackTrace();
      return;
      }

      String now = fmt.format(Calendar.getInstance().getTime());
      System.out.println("[" + now + "] woken up ok...");

      if (System.currentTimeMillis() - time > 1000) {
      System.err.println("Test failed");
      throw new RuntimeException("Test failed");
      }
      }
      }
      });

      Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

      thread.setPriority(Thread.MAX_PRIORITY);
      thread.setDaemon(true);
      thread.start();

      Thread.sleep(slp);

      new Calculator().doCalc(iter);


      // let the 'woken up' thread print some output
      Thread.sleep(1000);
      }

      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Workarounds:
      1) don't use 'for each' loops
      2) use interpreted mode only
      3) run the thread that prints keep-alives for more than 4000 ms before starting intensive computations
      4) perform some computations in the thread that prints keep-alives before starting another thread for computation
      5) use JRockit VM jdk1.6.0_29-R28.2.2-4.1.0, it works fine.

      Actually, 1) cannot be done because there are 3rd party libraries, 2) is very slow, 3) and 4) highly depend on the application and other threads in VM, 5) is not an option since JRockit is a commercial product expected to be discontinued.

            vlivanov Vladimir Ivanov
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: