线程的run()部分如下
public void run() {
System.out.println(_threadName + " starts to run.");
float updatedValue = 0;
try {

Connection conn = DatabaseHelper.getConnection();
updatedValue = _account.getBalance() + _amount;
System.out.println(_threadName + " before:" + _account.getBalance());
System.out.println(_threadName + " sleep.");
Thread.sleep(_delayedTime);
System.out.println(_threadName + " wake up.");
System.err.println(_threadName + " 1 balance = " + _account.getBalance());
_account.setBalance(updatedValue);
System.err.println(_threadName + " 2 balance = " + _account.getBalance());
System.out.println(_threadName + " after:"  + _account.getBalance());
conn.commit();
conn.close();

} catch (Exception e) {
e.printStackTrace();
}
System.out.println(_threadName + " stops running here.");
}
两个线程同时运行,线程1的_delayTime是3秒,线程2的_delayTime是1秒,我确定让线程2运行完,也就是在线程1对记录更新前,线程2已更新过。很明显,我是在模拟在没有锁的情况下记录操作的错误情况。问题是,当线程1醒来之后,“System.err.println(_threadName + " 1 balance = " + _account.getBalance());”输出的记录却是线程2更新前的值,我曾延长过_delayTime去看数据库中的记录,确实已经被线程2更新。问题:为什么会出现这种情况?怎样修改才能让线程1中的“System.err.println(_threadName + " 1 balance = " + _account.getBalance());”输出的记录却是线程2更新后的值?先谢谢大家了。

解决方案 »

  1.   

    _account对象没有同步,线程2退出时,线程1的_account还是线程1的工作内存中的值。所以_account.getBalance()还是原来的的值,只有对_account对象同步,才能保证线程2退出时,它更新的值才会写到主内存中,而线程2进入同步块前也会从主内存复制新值到自己的工作内存中。没有同步时,不同JVM实现 的行为不一样,有的可能也会从回写到方内存和从主内存复制,但一般为了优化,如果没有同步,会直接从自己的工作内存拿数据,如果编译器足够聪明,中间过程根本不复制,只保证最后结果回写。比如在多线程中,其中一个线程 for(int i=0;i<100;i++) x ++;
    这个线程不会每把x+1都让其它线程看到,也就是你用另一个线程看x的值,并不是看到一直加了100次,那个线程会等到100次加完后把最后的值写到主内存中,其它线程直接看到最后的结果。但如果是在同步块中,只要离开同步块,新值就一定会写到主内存中,其它线程在进入同步前也一会从主内存重取一次。
      

  2.   

    http://blog.csdn.net/axman/archive/2006/08/19/1097541.aspx