• Martin Thoma
  • Home
  • Categories
  • Tags
  • Archives
  • Support me

Java Puzzle #5: Parallel Programming, Part 2

Contents

  • Answer
  • Explanaition
  • Resolve this problem
  • A side note
  • See also

What is the output of the following script:

public class test {
    public static int globalVar;

    public static void main(String[] args) {
        globalVar = 1;

        MyParallelClass a = new MyParallelClass();
        MyParallelClass b = new MyParallelClass();

        new Thread(a).start();
        new Thread(b).start();

        System.out.println(globalVar);
    }
}
public class MyParallelClass implements java.lang.Runnable {
    public int counter = 0;

    @Override
    public void run() {
        if (test.globalVar > 0) {
            for (int i = 0; i < 1000000; i++) {
                counter++;
            }
            test.globalVar--;
        }
    }
}

. . . . . . . . . . . . . . . . .

Answer

0, 1 or -1.

Explanaition

First the simple ones: 0 is the result you would expect. One thread executes and reduces globalVar to 0, the other one does nothing and then globalVar gets printed.

If the main program is faster than any of the two threads, it prints 1 before globalVar gets reduced.

Now the most interesting one: -1. This is called a race condition. You have to know that globalVar-- is not an atomic operation. First you have to get the value, then you have to reduce it and after that you can save the value.

This is an order of execution which would lead to a wrong value:

First Thread Second Thread test.globalVar
```text checks if (globalVar > 0) looping ... looping ... execute test.globalVar--; ``` ```text . checks if (globalVar > 0) execute all four bytecode commands of "test.globalVar--;" . ``` ```text 1 1 0 -1 ```

Resolve this problem

  • Use join() if you don't want to get 1 as output.
  • If you don't want to get -1, you should take a look at the keyword synchronised.

A side note

With javap -c MyParallelClass you can view the bytecode of the class MyParallelClass. It looks like this:

Compiled from "MyParallelClass.java"
public class MyParallelClass extends java.lang.Object
                        implements java.lang.Runnable{
public int counter;

public MyParallelClass();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   iconst_0
   6:   putfield    #2; //Field counter:I
   9:   return

public void run();
  Code:
   0:   getstatic   #3; //Field test.globalVar:I
   3:   ifle    38
   6:   iconst_0
   7:   istore_1
   8:   iload_1
   9:   ldc #4; //int 1000000
   11:  if_icmpge   30
   14:  aload_0
   15:  dup
   16:  getfield    #2; //Field counter:I
   19:  iconst_1
   20:  iadd
   21:  putfield    #2; //Field counter:I
   24:  iinc    1, 1
   27:  goto    8
   30:  getstatic   #3; //Field test.globalVar:I
   33:  iconst_1
   34:  isub
   35:  putstatic   #3; //Field test.globalVar:I
   38:  return

}

Some links to the reference: getstatic, iconst_1, isub, putstatic

The interesting part of the bytecode is:

   30:  getstatic   #3; //Field test.globalVar:I
   33:  iconst_1
   34:  isub
   35:  putstatic   #3; //Field test.globalVar:I

You can see that the JVM has to execute 4 commands for test.globalVar--;.

See also

  • Atomic Access in Java
  • Class Monitor
  • monitorenter and monitorexit
  • Package java.util.concurrent

Published

Aug 3, 2012
by Martin Thoma

Category

Code

Tags

  • Java 36
  • Programming 52
  • puzzle 22
  • SWT I 9

Contact

  • Martin Thoma - A blog about Code, the Web and Cyberculture
  • E-mail subscription
  • RSS-Feed
  • Privacy/Datenschutzerklärung
  • Impressum
  • Powered by Pelican. Theme: Elegant by Talha Mansoor