Sample code is as this:
package SynTest;
public class Test01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Account account = new Account(100,"account");
SafeDrawing a = new SafeDrawing(account,80,"a");
SafeDrawing b = new SafeDrawing(account,80,"b");
a.start();
b.start();
}
}
class Account{
int money;
String name;
public Account(int money,String name) {
this.money = money;
this.name = name;
}
}
class SafeDrawing extends Thread{
volatile Account account;
int drawingMoney;
int packetTotal;
public SafeDrawing(Account account,int drawingMoney,String name) {
super(name);
this.account = account;
this.drawingMoney = drawingMoney;
}
public void test(){
System.out.println(Thread.currentThread().getName()+" comes in!");
if(account.money-drawingMoney<0) {
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
account.money -= drawingMoney;
packetTotal += drawingMoney;
System.out.println(this.getName()+"-->account remains:"+account.money);
System.out.println(this.getName()+"-->money in packet:"+packetTotal);
System.out.println(Thread.currentThread().getName()+" comes out!");
}
@Override
public void run() {
test();
}
}
Two threads are startd in main, and each of them owns a same object named account. And each thread reduces the money property of account, which should be bigger than 0;
Now the method test() is obviously unsafe, so the account.money can be less than 0, just like:
b comes in!
a comes in!
b-->account remains:-60
a-->account remains:-60
a-->money in packet:80
b-->money in packet:80
a comes out!
b comes out!
But when I kept running this code once and once again, I found an output like this:
a comes in!
b comes in!
a-->account remains:20
b-->account remains:20
a-->money in packet:80
b-->money in packet:80
a comes out!
b comes out!
This is weird because since these two threads both have run to the line System.out.println(this.getName()+"-->account remains:"+account.money);
, the code account.money -= drawingMoney;
must have been executed twice too, and why the remaining money is 20 rather than -60? Even if the happen-beefore is considered, since the account is defined as volatile, it's still impossible to be 20 rather than -60. I just cant't figure it out, and thanks for any idea.