Java多線程同步中的兩個特殊類
|
Java語言內置了synchronized關鍵字用于對多線程進行同步,大大方便了Java中多線程程序的編寫。但是僅僅使用synchronized關鍵字還不能滿足對多線程進行同步的所有需要。大家知道,synchronized僅僅能夠對方法或者代碼塊進行同步,如果我們一個應用需要跨越多個方法進行同步,synchroinzed就不能勝任了。在C++中有很多同步機制,比如信號量、互斥體、臨屆區等。在Java中也可以在synchronized語言特性的基礎上,在更高層次構建這樣的同步工具,以方便我們的使用。
當前,廣為使用的是由Doug Lea編寫的一個Java中同步的工具包,可以在這兒了解更多這個包的詳細情況:
http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html
該工具包已經作為JSR166正處于JCP的控制下,即將作為JDK1.5的正式組成部分。本文并不打算詳細剖析這個工具包,而是對多種同步機制的一個介紹,同時給出這類同步機制的實例實現,這并不是工業級的實現。但其中會參考Doug Lea的這個同步包中的工業級實現的一些代碼片斷。
本例中還沿用上篇中的Account類,不過我們這兒編寫一個新的ATM類來模擬自動提款機,通過一個ATMTester的類,生成10個ATM線程,同時對John賬戶進行查詢、提款和存款操作。Account類做了一些改動,以便適應本篇的需要:
import java.util.HashMap; import java.util.Map; class Account { String name; //float amount; //使用一個Map模擬持久存儲 static Map storage = new HashMap(); static { storage.put("John", new Float(1000.0f)); storage.put("Mike", new Float(800.0f)); } public Account(String name) { //System.out.println("new account:" + name); this.name = name; //this.amount = ((Float)storage.get(name)).floatValue(); } public synchronized void deposit(float amt) { float amount = ((Float)storage.get(name)).floatValue(); storage.put(name, new Float(amount + amt)); } public synchronized void withdraw(float amt) throws InsufficientBalanceException { float amount = ((Float)storage.get(name)).floatValue(); if (amount >= amt) amount -= amt; else throw new InsufficientBalanceException(); storage.put(name, new Float(amount)); } public float getBalance() { float amount = ((Float)storage.get(name)).floatValue(); return amount; } } |
在新的Account類中,我們采用一個HashMap來存儲賬戶信息。Account由ATM類通過login登錄后使用:
public class ATM { Account acc; //作為演示,省略了密碼驗證 public boolean login(String name) { if (acc != null) throw new IllegalArgumentException("Already logged in!"); acc = new Account(name); return true; } public void deposit(float amt) { acc.deposit(amt); } public void withdraw(float amt) throws InsufficientBalanceException { acc.withdraw(amt); } public float getBalance() { return acc.getBalance(); } public void logout () { acc = null; } } |