我最近試圖圍繞一些Java多線程概念進行研究,並撰寫了一小段代碼,以幫助我理解內存可見性並儘可能地獲得同步。根據我讀過的內容,似乎我們鎖定的代碼量越小,程序的效率就越高(一般情況下)。我寫了一個小的類來幫助我瞭解一些我可能會遇到的同步問題:瞭解Java多線程中的內存可見性
public class BankAccount {
private int balance_;
public BankAccount(int initialBalance) {
if (initialBalance < 300) {
throw new IllegalArgumentException("Balance needs to be at least 300");
}
balance_ = initialBalance;
}
public void deposit(int amount) {
if (amount <= 0) {
throw new IllegalArgumentException("Deposit has to be positive");
}
// should be atomic assignment
// copy should also be non-shared as it's on each thread's stack
int copy = balance_;
// do the work on the thread-local copy of the balance. This work should
// not be visible to other threads till below synchronization
copy += amount;
synchronized(this) {
balance_ = copy; // make the new balance visible to other threads
}
}
public void withdraw(int amount) {
// should be atomic assignment
// copy should also be non-shared as it's on each thread's stack
int copy = balance_;
if (amount > copy) {
throw new IllegalArgumentException("Withdrawal has to be <= current balance");
}
copy -= amount;
synchronized (this) {
balance_ = copy; // update the balance and make it visible to other threads.
}
}
public synchronized getBalance() {
return balance_;
}
}
請忽略的事實是balance_應該是雙重的,而不是一個整數。我知道原始類型讀取/賦值是原子性的,除了雙精度和長整數,所以我選擇了簡單的整數
我試圖在函數中寫下注釋來描述我的想法。這個類是爲了獲得正確的同步以及最小化被鎖定的代碼量而編寫的。這裏是我的問題:
- 此編程是否正確?它會遇到任何數據/競爭條件嗎?所有的更新都可以被其他線程看到嗎?
- 這個代碼與僅僅進行方法級同步一樣有效嗎?我可以想象,隨着工作量的增加(這裏,它只是一個加法/減法),它可能導致顯着的性能問題,方法級同步。
- 此代碼可以更有效嗎?
「 balance_應該是一個double而不是一個整數「不,建議不要使用浮點類型來表示貨幣。 –
始終使用long或BigInteger作爲貨幣,永遠不會翻倍。 1.20€= 120. – dit
@dit我會說長或BigDecimal。如果你用很長時間來表示美分,2^63將會不夠。例如,以美分爲單位的世界GDP只有2^46美元左右。如果你的客戶擁有的資金比他們的賬戶更多,我會更少擔心BigInteger,更多的是關於肆意破壞全球經濟的通貨膨脹。 ;) – yshavit