Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Monday, June 20, 2016

How to demonstrate java multithreading visibility problems?

How to demonstrate java multithreading visibility problems?


If variables in Java are accessed from multiple threads, one must ensure that they are safely published. This usually means using synchronizedor volatile.

I have got the impression, that some of my colleagues do not take this issue seriously, since they "never heard of volatile before and their programs have worked for years".

So my question is:

Can someone provide an example Java program/snippet, that reliably shows data visibility problems.

I think running a program and seeing the unexpected NPE or stale variable value would help more, than just theoretic explanations, that cannot be demonstrated.

Thanks a lot for your help!

Update: Just to emphasis the point again. I have read Java Concurreny in Practice and know examples that theoretically have visibility issues. What I am looking for is a way to actually demonstrate them. I am not sure, that this is actually possible, but maybe there is a jvm configuration or something similar that allows it.

Answer by Jesper for How to demonstrate java multithreading visibility problems?


Make them read the book Java Concurrency in Practice by Java concurrency guru Brian Goetz. That book is a must-read for anybody who has to write any serious concurrent software in Java!

Ofcourse saying "I've never heard of volatile and my programs have worked for years" is a dumb argument from ignorance.

Answer by aioobe for How to demonstrate java multithreading visibility problems?


The most common example brought up to emphasis the importance of using volatile is the while(keepRunning) example:

public class Test extends Thread {        boolean keepRunning = true;        public static void main(String[] args) throws InterruptedException {          Test t = new Test();          t.start();          Thread.sleep(1000);          t.keepRunning = false;          System.out.println(System.currentTimeMillis() + ": keepRunning is false");      }        public void run() {          while (keepRunning)               System.out.println(System.currentTimeMillis() + ": " + keepRunning);      }  }  

Since keepRunning may (validly) be kept in cache of the thread running the while-loop, this program may print "true" for keepRunning long after keepRunning is set to false.

Note however, that there is no reliable way of exposing race-conditions. (See my other answer.) This example may expose it under certain circumstances on certain combinations of hardware / operating system / jvm.

Answer by aioobe for How to demonstrate java multithreading visibility problems?


Can someone provide an example Java program/snippet, that reliably shows data visibility problems.

No, there is no reliably example that shows data visibility problems.

The reason is that any valid execution of a program with volatile is also a valid execution of the same program without volatile. (The opposite is obviously not true though!)

Answer by David Rodrguez - dribeas for How to demonstrate java multithreading visibility problems?


By modifying the example here by removing operations I have come up with an example that consistently fails in my environment (the thread never stops running).

// Java environment:  // java version "1.6.0_0"  // OpenJDK Runtime Environment (IcedTea6 1.6.1) (6b16-1.6.1-3ubuntu3)  // OpenJDK 64-Bit Server VM (build 14.0-b16, mixed mode)  public class Test2 extends Thread {      boolean keepRunning = true;      public static void main(String[] args) throws InterruptedException {          Test2 t = new Test2();          t.start();          Thread.sleep(1000);          t.keepRunning = false;          System.out.println(System.currentTimeMillis() + ": keepRunning is false");      }      public void run() {          while (keepRunning)           {}      }  }  

Note that this type of problems are quite dependent on the compiler/runtime/system. In particular the compiler can determine to add instructions to read the variable from memory even if it is not volatile --so the code would work--, the vm and jit can optimize away the reads from memory and use only registers, and even the processor can reorder instructions --that would not affect this case, but in other multithreaded cases it can affect the perceived state from other threads if more than one variable are modified.

Answer by soil7c3 for How to demonstrate java multithreading visibility problems?


I have a snippet of code for you:

package test;    public class LoopTest {     private boolean done = false;     /**    * @param args    */   public void start() {    System.out.println(System.getProperty("java.vm.name"));    System.out.println(System.getProperty("java.version"));    for (int i = 0; i < 100; i++) {     startNewThread();    }      try {     Thread.sleep(1000);    } catch (InterruptedException e) {     e.printStackTrace();    }    done = true;    System.out.println("forcing end");   }     private void startNewThread() {    new Thread(new Runnable() {       public void run() {      long i = 0;      while(!done) {       i++;       if(i % 100L == 0) {        System.out.println("still working " + i);       }      }      System.out.println("ending " + i);     }      }).start();   }     public static void main(String[] args) {    new LoopTest().start();   }    }  

This example run in JVM Server mode generated this output on my machine:

..  ..  ending 14100  still working 14800  ending 14800  still working 26500  ending 26500  still working 18200  ending 18200  still working 9400  ending 9400  still working 1300  ending 1300  still working 59500  ending 59500  still working 1700  still working 75400  ending 75400  still working 33500  ending 33500  still working 36100  ending 36100  still working 121000  ending 121000  still working 3000  ending 3000  ending 1700  still working 5900  ending 5900  still working 7800  ending 7800  still working 7800  ending 7800  still working 6800  ending 6800  still working 5300  ending 5300  still working 9100  still working 10600  ending 10600  still working 9600  ending 9600  still working 10000  ending 10000  ending 9100  still working 1700  ending 1700  ..  ..  

Look at the "ending #" statements: all of them have a number which is a multiple of 100 which is quite unlikely to happen, i think. My interpretation is that there is an visibility issue which causes the threads to still read done == false although it already has been updated to true. After the call to the synchronized System.out.println() method with the "still working #" statement, the threads read the updated value for done and exit.

Or does anyone see a mistake in my code / interpretation?

Answer by Narendra Pathai for How to demonstrate java multithreading visibility problems?


public class NoVisibility {        private static boolean ready = false;      private static int number;        private static class ReaderThread extends Thread {            @Override          public void run() {              while (!ready) {                  Thread.yield();              }              System.out.println(number);          }      }        public static void main(String[] args) throws InterruptedException {          new ReaderThread().start();          number = 42;          Thread.sleep(20000);          ready = true;      }  }  

Place the Thread.sleep() call for 20 secs what will happen is JIT will kick in during those 20 secs and it will optimize the check and cache the value or remove the condition altogether. And so the code will fail on visibility.

To stop that from happening you MUST use volatile.

Answer by Biman Tripathy for How to demonstrate java multithreading visibility problems?


An extension to @David's code (configuration Java6 64bit, Eclipse Juno SR2):

public class NoVisibility_Demonstration extends Thread {      boolean keepRunning = true;      public static void main(String[] args) throws InterruptedException {          NoVisibility_Demonstration t = new NoVisibility_Demonstration();          t.start();          Thread.sleep(1000);          t.keepRunning = false;          System.out.println(System.currentTimeMillis() + ": keepRunning is false");      }      public void run() {          int x = 10;          while (keepRunning)           {              //System.out.println("If you uncomment this line, the code will work without the visibility issue");              x++;            }          System.out.println("x:"+x);      }  }  

Using this example, you can show both scenarios. When you uncomment the line in the while loop in run(), the visibility issue is resolved. The reason is that println() statements use synchronization. Detailed discussion HERE


Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72

0 comments:

Post a Comment

Popular Posts

Powered by Blogger.