控制台程序。
在这个版本的银行示例中,把借款和贷款事务创建为在不同线程中执行的任务,它们把事务提交给职员。创建事务的任务是Callable<>任务,因为它们需要返回已为每个账户创建的借款或贷款事务的总额。
1 // Defines a customer account 2 public class Account { 3 // Constructor 4 public Account(int accountNumber, int balance) { 5 this.accountNumber = accountNumber; // Set the account number 6 this.balance = balance; // Set the initial balance 7 } 8 9 // Return the current balance 10 public int getBalance() { 11 return balance; 12 } 13 14 // Set the current balance 15 public void setBalance(int balance) { 16 this.balance = balance; 17 } 18 19 public int getAccountNumber() { 20 return accountNumber; 21 } 22 23 @Override 24 public String toString() { 25 return "A/C No. " + accountNumber + " : $" + balance; 26 } 27 28 private int balance; // The current account balance 29 private int accountNumber; // Identifies this account 30 }
1 // Bank account transaction types 2 public enum TransactionType {DEBIT, CREDIT }
1 public class Transaction { 2 // Constructor 3 public Transaction(Account account, TransactionType type, int amount) { 4 this.account = account; 5 this.type = type; 6 this.amount = amount; 7 } 8 9 public Account getAccount() { 10 return account; 11 } 12 13 public TransactionType getTransactionType() { 14 return type; 15 } 16 17 public int getAmount() { 18 return amount; 19 } 20 @Override 21 public String toString() { 22 return type + " A//C: " + ": $" + amount; 23 } 24 25 private Account account; 26 private int amount; 27 private TransactionType type; 28 }
1 // Define the bank 2 3 public class Bank { 4 // Perform a transaction 5 public void doTransaction(Transaction transaction) { 6 synchronized(transaction.getAccount()) { 7 int balance = 0; 8 switch(transaction.getTransactionType()) { 9 case CREDIT: 10 System.out.println("Start credit of " + 11 transaction.getAccount() + " amount: " + 12 transaction.getAmount()); 13 14 // Get current balance 15 balance = transaction.getAccount().getBalance(); 16 17 // Credits require a lot of checks... 18 try { 19 Thread.sleep(100); 20 21 } catch(InterruptedException e) { 22 System.out.println(e); 23 } 24 balance += transaction.getAmount(); // Increment the balance 25 transaction.getAccount().setBalance(balance); // Restore account balance 26 System.out.println(" End credit of " + 27 transaction.getAccount() + " amount: " + 28 transaction.getAmount()); 29 break; 30 case DEBIT: 31 System.out.println("Start debit of " + 32 transaction.getAccount() + " amount: " + 33 transaction.getAmount()); 34 35 // Get current balance 36 balance = transaction.getAccount().getBalance(); 37 38 // Debits require even more checks... 39 try { 40 Thread.sleep(150); 41 42 } catch(InterruptedException e) { 43 System.out.println(e); 44 } 45 balance -= transaction.getAmount(); // Decrement the balance... 46 transaction.getAccount().setBalance(balance); // Restore account balance 47 48 System.out.println(" End debit of " + 49 transaction.getAccount() + " amount: " + 50 transaction.getAmount()); 51 break; 52 53 default: // We should never get here 54 System.out.println("Invalid transaction"); 55 System.exit(1); 56 } 57 } 58 } 59 }
1 import java.util.List; 2 import java.util.Collections; 3 import java.util.LinkedList; 4 5 public class Clerk implements Runnable { 6 // Constructor 7 public Clerk(int ID, Bank theBank) { 8 this.ID = ID; 9 this.theBank = theBank; // Who the clerk works for 10 } 11 12 // Receive a transaction 13 synchronized public boolean doTransaction(Transaction transaction) { 14 if(inTray.size() >= maxTransactions) 15 return false; 16 inTray.add(transaction); // Add transaction to the list 17 return true; 18 } 19 20 // The working clerk... 21 public void run() { 22 while(true) { 23 while(inTray.size() == 0) { // No transaction waiting? 24 try { 25 Thread.sleep(200); // then take a break 26 if(inTray.size() != 0) { 27 break; 28 } else { 29 return; 30 } 31 } catch(InterruptedException e) { 32 System.out.println("Clerk "+ ID + " " + e); 33 return; 34 } 35 } 36 theBank.doTransaction(inTray.remove(0)); 37 if(Thread.interrupted()) { 38 System.out.println("Interrupt flag for Clerk " + ID + " set. Terminating."); 39 return; 40 } 41 } 42 } 43 44 int ID; 45 private Bank theBank; 46 private List<Transaction> inTray = // The in-tray holding transactions 47 Collections.synchronizedList(new LinkedList<Transaction>()); 48 private int maxTransactions = 8; // Maximum transactions in the in-tray 49 }
1 // Generates transactions for clerks 2 import java.util.Random; 3 import java.util.Vector; 4 import java.util.concurrent.Callable; 5 6 public class TransactionSource implements Callable<int[]> { 7 8 public TransactionSource(TransactionType type, int maxTrans, Vector<Account> accounts, Vector<Clerk> clerks) { 9 this.type = type; 10 this.maxTrans = maxTrans; 11 this.accounts = accounts; 12 this.clerks = clerks; 13 totals = new int[accounts.size()]; 14 } 15 16 // The source of transactions 17 public int[] call() { 18 // Create transactions randomly distributed between the accounts 19 Random rand = new Random(); 20 Transaction transaction = null; // Stores a transaction 21 int amount = 0; // Stores an amount of money 22 int select = 0; // Selects an account 23 boolean done = false; 24 for(int i = 1 ; i <= maxTrans ; ++i) { 25 // Generate a random account index for operation 26 select = rand.nextInt(accounts.size()); 27 amount = 50 + rand.nextInt(26); // Generate amount of $50 to $75 28 transaction = new Transaction(accounts.get(select), // Account 29 type, // Transaction type 30 amount); // of amount 31 totals[select] += amount; // Keep total tally for account 32 done = false; 33 while(true) { 34 // Find a clerk to do the transaction 35 for(Clerk clerk : clerks) { 36 if(done = clerk.doTransaction(transaction)) 37 break; 38 } 39 if(done) { 40 break; 41 } 42 43 // No clerk was free so wait a while 44 try { 45 Thread.sleep(10); 46 } catch(InterruptedException e) { 47 System.out.println(" TransactionSource " + e); 48 return totals; 49 } 50 } 51 if(Thread.interrupted()) { 52 System.out.println("Interrupt flag for "+ type + " transaction source set. Terminating."); 53 return totals; 54 } 55 } 56 return totals; 57 } 58 59 private TransactionType type; 60 private int maxTrans; 61 private Vector<Account> accounts; 62 private Vector<Clerk> clerks; 63 private int[] totals; 64 }
1 import java.util.Vector; 2 import java.util.concurrent.Executors; 3 import java.util.concurrent.ExecutorService; 4 import java.util.concurrent.Future; 5 import java.util.concurrent.ExecutionException; 6 import java.util.concurrent.TimeUnit; 7 8 public class UsingExecutors { 9 10 public static void main(String[] args) { 11 int[] initialBalance = {500, 800}; // The initial account balances 12 int[] totalCredits = new int[initialBalance.length]; // Two different cr totals 13 int[] totalDebits = new int[initialBalance.length]; // Two different db totals 14 int transactionCount = 20; // Number of debits and of credits 15 int clerkCount = 2; 16 17 // Create the account, the bank, and the clerks... 18 Bank theBank = new Bank(); // Create a bank 19 Vector<Clerk> clerks = new Vector<Clerk>(); // Stores the clerk 20 Vector<Account> accounts = new Vector<Account>(); // Stores the accounts 21 22 for(int i = 0 ; i < clerkCount ; ++i) { 23 clerks.add(new Clerk(i+1, theBank)); // Create the clerks 24 } 25 26 for(int i = 0 ; i < initialBalance.length; ++i) { 27 accounts.add(new Account(i+1, initialBalance[i])); // Create accounts 28 totalCredits[i] = totalDebits[i] = 0; 29 } 30 31 ExecutorService threadPool = Executors.newCachedThreadPool(); 32 33 // Create and start the transaction source threads 34 Future<int[]> credits = threadPool.submit(new TransactionSource(TransactionType.CREDIT, transactionCount, accounts, clerks)); 35 Future<int[]> debits = threadPool.submit(new TransactionSource(TransactionType.DEBIT, transactionCount, accounts, clerks)); 36 37 // Create and start the clerk threads 38 for(Clerk clerk : clerks) { 39 threadPool.submit(clerk); 40 } 41 try { 42 totalCredits = credits.get(); 43 totalDebits = debits.get(); 44 } catch(ExecutionException e) { 45 System.out.println(e.getCause()); 46 } catch(InterruptedException e) { 47 System.out.println(e); 48 } 49 50 // Orderly shutdown when all threads have ended 51 threadPool.shutdown(); 52 try { 53 threadPool.awaitTermination(10L, TimeUnit.SECONDS); 54 } catch(InterruptedException e) { 55 System.out.println(e); 56 } 57 58 if(threadPool.isTerminated()) { 59 System.out.println(" All clerks have completed their tasks. "); 60 } else { 61 System.out.println(" Clerks still running - shutting down anyway. "); 62 threadPool.shutdownNow(); 63 } 64 65 // Now output the results 66 for(int i = 0 ; i < accounts.size() ; ++i) { 67 System.out.println("Account Number:"+accounts.get(i).getAccountNumber()+" "+ 68 "Original balance : $" + initialBalance[i] + " " + 69 "Total credits : $" + totalCredits[i] + " " + 70 "Total debits : $" + totalDebits[i] + " " + 71 "Final balance : $" + accounts.get(i).getBalance() + " " + 72 "Should be : $" + (initialBalance[i] 73 + totalCredits[i] 74 - totalDebits[i]) + " "); 75 } 76 } 77 }