views:

121

answers:

2

I am new to Java and I'm attending a Concurrent Programming course. I am desperately trying to get a minimal working example that can help to demonstrate concepts I have learnt like using 'synchronized' keyword and sharing an object across threads. Have been searching, but could not get a basic framework. Java programmers, kindly help.

+5  A: 

A simple example. Hope you like soccer (or football). :)

public class Game {

 public static void main(String[] args) {
  Ball gameBall = new Ball();
  Runnable playerOne = new Player("Pasha", gameBall);
  Runnable playerTwo = new Player("Maxi", gameBall);

  new Thread(playerOne).start();
  new Thread(playerTwo).start();
 }

}

public class Player implements Runnable {

 private final String name;
 private final Ball ball;

 public Player(String aName, Ball aBall) {
  name = aName;
  ball = aBall;
 }

 @Override
 public void run() {
  while(true) {
   ball.kick(name);
  }
 }

}

public class Ball {

private String log;

 public Ball() {
  log = "";
 }

 //Removing the synchronized keyword will cause a race condition.
 public synchronized void kick(String aPlayerName) {
  log += aPlayerName + " ";
 }

 public String getLog() {
  return log;
 }

}
Mike
How does this show a race condition?
jjnguy
Instantiate a few more Player objects to make it more obvious.
Mike
As far as I can see, it will alternate between player names. But, not necessarily every other, because that's just how context switching works.
jjnguy
Instantiate a few more, remove the synchronized keyword. ThreadA moves into call System.out.println(). ThreadB does so shortly after. Blammo.
Mike
@Mike, Ok, I will try it myself before I criticize.
jjnguy
It's okay. Double check me. :)
Mike
@Mike: Isn't `System.out.println` synchronized?
Daniel Trebbien
Google says yes. Learn something new every day. I'll modify my example. Thanks. :)
Mike
Hmmm, I guess I don't see it...
jjnguy
@Mike: You could append the strings to an `ArrayList<String>`. That's what I was thinking originally as a good example (i.e., two threads calling a thread-unsafe method on the same object without proper synchronization).
Daniel Trebbien
@Dan, what did you think of my example?
jjnguy
@Justin: I think that that works, the reason being that the `--` and `++` operations are not atomic. It might take many runs of this program to see the problem, however, because both threads would have to iterate from 0 to 400,000 in lock step. One note: Instead of having the current thread sleep, you could join the current thread on both of the threads that you started.
Daniel Trebbien
@Dan, with running 4000 times through, you do see a little bit of error in the results.
jjnguy
@Justin: Wow! I didn't expect it, but there were *a lot* of errors the first time that I ran it. Interesting.
Daniel Trebbien
+2  A: 

Here is a very shot example of sharing an array between two threads. Usually you will see all zeros, but sometimes things get screwy and you see other numbers.

final int[] arr = new int[100];
Thread one = new Thread() {
    public void run() {
        // synchronized (arr) {
            for (int i = 0; i < arr.length * 100000; i++) {
                arr[i % arr.length]--;
            }
        // }
    }
};
Thread two = new Thread() {
    public void run() {
        // synchronized (arr) {
            for (int i = 0; i < arr.length * 100000; i++) {
                arr[i % arr.length]++;
            }
        //}
    }
};
one.start();
two.start();
one.join();
two.join();
for (int i = 0; i < arr.length; i++) {
    System.out.println(arr[i]);
}

But, if you synchronize on arr around the looping you will always see all 0s in the print out. If you uncomment the synchronized block, the code will run without error.

jjnguy
You can also get rid of the errors by synchronizing on `arr` for just the increment and decrement lines: http://pastebin.com/vN4E527P This underscores the fact that the only thread-unsafe parts are those two lines.
Daniel Trebbien
Sometimes I am getting a string of random numbers. I am puzzled. Can u kindly explain the working?
iJeeves
Shouldn't arr[i % arr.length]-- and arr[i % arr.length]++ balance out as it is being executed the same number of times? In other words shouldn't the result be zero always?
iJeeves
@n0vi Yea, that is exactly why this is a great example of problems caused by sharing objects over multiple threads. What happens is the two threads try to increment and decrement the same item in the array at the same time, and one overwrites the other, so you don't see all `0` like you should.
jjnguy
thanks a ton for the explanation and the example.
iJeeves
@iJee, no problem. Glad to help.
jjnguy