I was doing tutorial on concurrent programming and saw .join() method is used to make sure the thread will run until finish before continue the rest of code.
However, when i trying use 2 thread to increment and decrements a variable like 100 times (initiate value: 2000), the end result suppose to show 2000, but it show either more than 2000 or less than 2000.
It only works fine and consistently show 2000 when i uncomment the Thread.sleep
in main method
public class Main {
public static void main(String[] args) {
SharedObj sharedObj = new SharedObj();
Thread thread1 = new Thread(new ThreadMinus(sharedObj));
Thread thread2 = new Thread(new ThreadPlus(sharedObj));
thread1.start();
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("number is: " + sharedObj.num);
System.out.println("increment count: " + sharedObj.countPos);
System.out.println("decrement count: " + sharedObj.countNeg);
}
}
class SharedObj {
public int num;
public int countPos = 0;
public int countNeg = 0;
public SharedObj() {
num = 2000;
}
public void change(int x) {
num += x;
if (x < 0) {
countNeg++;
} else {
countPos++;
}
System.out.println("number is: " + num + " with operation: " + x);
}
}
class ThreadMinus implements Runnable {
SharedObj sharedObj;
public ThreadMinus(SharedObj sharedObj) {
this.sharedObj = sharedObj;
}
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
sharedObj.change(-1);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class ThreadPlus implements Runnable {
SharedObj sharedObj;
public ThreadPlus(SharedObj sharedObj) {
this.sharedObj = sharedObj;
}
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
sharedObj.change(+1);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
It's not the sleep/join causing problems. It's the race condition that you're incrementing the same variable without securing it. Add synchronized
to SharedObj#change and you should be fine:
public synchronized void change(int x) { //...