我想請問一下我這邊用同步代碼塊synchronize來實作同步的時候,如果代碼塊里沒有添加sleep或者在main方法里添加sleep的時候,最后結果還是會出現synchronize不生效的情況,一旦把物件鎖起來之后,后續執行緒不是應該等待鑰匙的歸還么?運行的結果如下:
Thread-0取出后賬戶acd1的剩余余額為:80000
Thread-1取出后賬戶acd1的剩余余額為:80000
Thread-2取出后賬戶acd2的剩余余額為:10000
Thread-3取出后賬戶acd2的剩余余額為:0
public class TakeMoneyTest {
public static void main(String[] args) {
BankUser acd1 = new BankUser("acd1", 100000);
BankUser acd2 = new BankUser("acd2", 20000);
Thread thread1 = new Thread(new GetMoney(acd1));
thread1.start();
/*try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
Thread thread2 = new Thread(new GetMoney(acd1));
thread2.start();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread thread3 = new Thread(new GetMoney(acd2));
thread3.start();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread thread4 = new Thread(new GetMoney(acd2));
thread4.start();
}
}
class BankUser {
private String bankAcount;
private int money;
public BankUser(){
}
public BankUser(String bankAcount, int money){
this.bankAcount = bankAcount;
this.money = money;
}
public String getBankAcount() {
return bankAcount;
}
public int getMoney() {
return money;
}
public void setBankAccount(String bankAcount) {
this.bankAcount = bankAcount;
}
public void setMoney(int money) {
this.money = money;
}
Integer intMoney = (Integer)money;
public void withdraw(int money) {
synchronized (this.intMoney){
int before = this.getMoney();
int after = before - money;
this.setMoney(after);
}
}
}
class GetMoney implements Runnable {
private BankUser bankUser;
public GetMoney(BankUser bankUser) {
this.bankUser = bankUser;
}
@Override
public void run() {
this.bankUser.withdraw(10000);
System.out.println(Thread.currentThread().getName() + "取出后"+"賬戶"+ bankUser.getBankAcount()+"的剩余余額為:" + bankUser.getMoney());
}
}麻煩各位大佬了
,這個bug無法理解
uj5u.com熱心網友回復:
首先一個問題, getMoney最好也synchronize, 雖說 其它執行緒是synchronize 修改 money, 但為了避免一些不一致的情況, 加上sync 比較保險,public int getMoney() {
synchronized (this.intMoney){
return money;
}
}
另外一個問題, 當在GetMoney中執行時 withdraw(10000); 后, 作業系統有可能調度其它執行緒執行, 所以, 后面的 getMoney() 有可能回傳的和
預想的不一致,
@Override
public void run() {
this.bankUser.withdraw(10000); // 執行完這句, 作業系統調度其它執行緒
System.out.println(Thread.currentThread().getName() + "取出后"+"賬戶"+ bankUser.getBankAcount()+"的剩余余額為:" + bankUser.getMoney());
}
例如: acc1有 10W,
執行緒1執行 withdraw(1W); 作業系統調度執行 執行緒2 withdraw(1W); 然后又回傳執行緒1執行下面print陳述句
System.out.println(Thread.currentThread().getName() + "取出后"+"賬戶"+ bankUser.getBankAcount()+"的剩余余額為:" + bankUser.getMoney());
這時, 執行緒1列印出余額是8w, 而不是設想的9W
所以, 建議修改withdraw介面, 讓它也回傳余額,比如:
public int withdraw2(int money) {
synchronized (this.intMoney){
this.money -= money;
return this.money;
}
}
當然,多執行緒是個比較復雜的問題,一些tutorial,
https://docs.oracle.com/javase/tutorial/essential/concurrency/index.html
"Thinking in java" 電子書 這些
完整代碼
public class TakeMoneyTest {
public static void main(String[] args) {
BankUser acd1 = new BankUser("acd1", 100000);
BankUser acd2 = new BankUser("acd2", 20000);
Thread thread1 = new Thread(new GetMoney(acd1));
thread1.start();
/*try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
Thread thread2 = new Thread(new GetMoney(acd1));
thread2.start();
try {
Thread.sleep(1);
}
catch (InterruptedException e) {
e.printStackTrace();
}
Thread thread3 = new Thread(new GetMoney(acd2));
thread3.start();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread thread4 = new Thread(new GetMoney(acd2));
thread4.start();
}
}
class BankUser {
private String bankAcount;
private int money;
public BankUser(){
}
public BankUser(String bankAcount, int money){
this.bankAcount = bankAcount;
this.money = money;
}
public String getBankAcount() {
return bankAcount;
}
// public int getMoney() {
// return money;
// }
public int getMoney() {
synchronized (this.intMoney){
return money;
}
}
public void setBankAccount(String bankAcount) {
this.bankAcount = bankAcount;
}
public void setMoney(int money) {
this.money = money;
}
Integer intMoney = (Integer)money;
// public void withdraw(int money) {
// synchronized (this.intMoney){
// int before = this.getMoney();
// int after = before - money;
// this.setMoney(after);
// }
// }
public void withdraw(int money) {
synchronized (this.intMoney){
this.money -= money;
}
}
public int withdraw2(int money) {
synchronized (this.intMoney){
this.money -= money;
return this.money;
}
}
}
class GetMoney implements Runnable {
private BankUser bankUser;
public GetMoney(BankUser bankUser) {
this.bankUser = bankUser;
}
@Override
public void run() {
int ret = this.bankUser.withdraw2(10000);
//System.out.println(Thread.currentThread().getName() + "取出后"+"賬戶"+ bankUser.getBankAcount()+"的剩余余額為:" + bankUser.getMoney());
System.out.println(Thread.currentThread().getName() + "取出后"+"賬戶"+ bankUser.getBankAcount()+"的剩余余額為:" + ret);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/195432.html
標籤:Java相關
上一篇:關于建行網銀退款
