Java Synchronization Real Time Example

Java Synchronization

Next, let's look at a quick example of a race condition in Java, just so we can see how it could occur in our code.

Poorly Designed Multithreading

First, let's consider this example:

                          public              class              MyData              {              public              int              x;              }                      
                          import              java.lang.Runnable;              import              java.lang.Thread;              import              java.lang.InterruptedException;              public              class              MyThread              implements              Runnable              {              private              String name;              private              static              MyData data;              /**                                            * Constructor.                                            *                                            * @param name the name of the thread                                            */              public              MyThread              (String name)              {              this              .              name              =              name;              }              /**                                            * Thread method.                                            *                                            * <p>This is called when the thread is started.                                            */              @Override              public              void              run              ()              {              for              (              int              i              =              0;              i              <              3;              i++)              {              int              y              =              data.              x              ;              // tell the OS it is ok to switch to another thread here                                          Thread.              yield              ();              data.              x              =              y              +              1;              System.              out              .              println              (              this              .              name              +              " : data.x = "              +              data.              x              );              }              }              /**                                            * Main Method.                                            */              public              static              void              main              (String[]              args)              {              // create data                                          data              =              new              MyData();              // create threads                                          Thread thread1              =              new              Thread(              new              MyThread(              "Thread 1"              ));              Thread thread2              =              new              Thread(              new              MyThread(              "Thread 2"              ));              Thread thread3              =              new              Thread(              new              MyThread(              "Thread 3"              ));              // start threads                                          System.              out              .              println              (              "main: starting threads"              );              thread1.              start              ();              thread2.              start              ();              thread3.              start              ();              // wait until all threads have terminated                                          System.              out              .              println              (              "main: joining threads"              );              try              {              thread1.              join              ();              thread2.              join              ();              thread3.              join              ();              }              catch              (InterruptedException e){              System.              out              .              println              (              "main thread was interrupted"              );              }              System.              out              .              println              (              "main: all threads terminated"              );              System.              out              .              println              (              "main: data.x = "              +              data.              x              );              }              }                      

Explanation

In this example, we are creating a static instance of the MyData class, which can act as a shared memory object for this example. Then, in each of the threads, we are performing this three-step process:

                          int              y              =              data.              x              ;              // tell the OS it is ok to switch to another thread here                            Thread.              yield              ();              data.              x              =              y              +              1;                      

Just as we saw in the earlier example, we are reading the current value stored in data.x into a variable y. Then, we are using the Thread.yield() method to tell the operating system that it is allowed to switch away from this thread at this point. In practice, we typically wouldn't use this method at all, but it is helpful for testing. In fact, Thread.yield() is effectively the same as calling Thread.sleep(0) - we are telling the operating system to put this thread to sleep, but then immediately add it back to the list of threads to be scheduled on the processor. Finally, we update the value stored in data.x to be one larger than the value we saved earlier.

In effect, this is essentially the Java code needed to reproduce the example we saw earlier in this class.

Execution

So, what happens when we run this code? As it turns out, sometimes we'll see it get a different result than the one we expect:

Race Condition in Java

Uh oh! This is exactly what a race condition looks like in practice. In the screenshot on the right, we see that two threads set the same value into data.x, which means that they were running at the same time.

Java Synchronized Blocks

To fix this, Java includes couple of special methods for dealing with synchronization. First, we can use the synchronized statement, which is simply a wrapper around a block of code that we'd like to be atomic. An atomic block is one that shouldn't be broken apart and interrupted by other threads accessing the same object. In effect, the synchronized statement will handle acquiring and releasing a lock for us, based on the item used in the statement.

So, in this example, we can update the run() method to use a synchronized statement:

                          @Override              public              void              run              ()              {              for              (              int              i              =              0;              i              <              3;              i++)              {              synchronized              (data)              {              int              y              =              data.              x              ;              Thread.              yield              ();              data.              x              =              y              +              1;              System.              out              .              println              (              this              .              name              +              " : data.x = "              +              data.              x              );              }              Thread.              yield              ();              }              }                      

Here, the synchronized statement creates a lock that is associated with the data object in memory. Only one thread can hold that lock at a time, and by associating it with an object, we can easily keep track of which thread is able to access that object.

Now, when we execute that program, we'll always get the correct answer!

Synchronized in Java

Not Always Random?

In fact, to get the threads interleaved as shown in this screenshot, we had to add additional Thread.sleep() statements to the code! Otherwise, the program always seemed to schedule the threads in the same order on Codio. We cannot guarantee it will always happen like that, but it is an interesting quirk you can observe in multithreaded code. In practice, sometimes race conditions may only happen once in a million operations, making them extremely difficult to debug when they happen.

ogleshitery.blogspot.com

Source: https://textbooks.cs.ksu.edu/cc410/ii-gui/10-parallelism/08-java-synchronization/

0 Response to "Java Synchronization Real Time Example"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel