控制台程序。
除了同步类对象的方法之外,还可以把程序中的语句或代码块制定为synchronized,这种方式更强大,因为可以指定哪个对象从语句或代码块的同步中获益,而不像同步方法那样仅仅是包含代码的对象能获益。这里可以对给定代码块的任何对象设置锁。当对给定对象执行同步的代码块时,就不能执行对相同对象同步的其他代码或方法。
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: " + account + ": $" + 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 switch(transaction.getTransactionType()) { 7 case CREDIT: 8 synchronized(transaction.getAccount()) { 9 System.out.println("Start credit of " + 10 transaction.getAccount() + " amount: " + 11 transaction.getAmount()); 12 13 // Get current balance 14 int balance = transaction.getAccount().getBalance(); 15 16 // Credits require a lot of checks... 17 try { 18 Thread.sleep(100); 19 20 } catch(InterruptedException e) { 21 System.out.println(e); 22 } 23 balance += transaction.getAmount(); // Increment the balance 24 transaction.getAccount().setBalance(balance); // Restore account balance 25 System.out.println(" End credit of " + 26 transaction.getAccount() + " amount: " + 27 transaction.getAmount()); 28 break; 29 } 30 case DEBIT: 31 synchronized(transaction.getAccount()) { 32 System.out.println("Start debit of " + 33 transaction.getAccount() + " amount: " + 34 transaction.getAmount()); 35 36 // Get current balance 37 int balance = transaction.getAccount().getBalance(); 38 39 // Debits require even more checks... 40 try { 41 Thread.sleep(150); 42 43 } catch(InterruptedException e) { 44 System.out.println(e); 45 } 46 balance -= transaction.getAmount(); // Decrement the balance... 47 transaction.getAccount().setBalance(balance); // Restore account balance 48 49 System.out.println(" End debit of " + 50 transaction.getAccount() + " amount: " + 51 transaction.getAmount()); 52 break; 53 } 54 55 default: // We should never get here 56 System.out.println("Invalid transaction"); 57 System.exit(1); 58 } 59 } 60 }
1 public class Clerk implements Runnable { 2 // Constructor 3 public Clerk(Bank theBank) { 4 this.theBank = theBank; // Who the clerk works for 5 inTray = null; // No transaction initially 6 } 7 8 // Receive a transaction 9 public void doTransaction(Transaction transaction) { 10 inTray = transaction; 11 } 12 13 // The working clerk... 14 public void run() { 15 while(true) { // Non-stop work... 16 while(inTray == null) { // No transaction waiting? 17 try { 18 Thread.sleep(150); // Then take a break... 19 20 } catch(InterruptedException e) { 21 System.out.println(e); 22 } 23 } 24 25 theBank.doTransaction(inTray); 26 inTray = null; // In-tray is empty 27 } 28 } 29 30 // Busy check 31 public boolean isBusy() { 32 return inTray != null; // A full in-tray means busy! 33 } 34 35 private Bank theBank; // The employer - an electronic marvel 36 private Transaction inTray; // The in-tray holding a transaction 37 }
1 import java.util.Random; 2 3 public class BankOperation4 { 4 public static void main(String[] args) { 5 int[] initialBalance = {500, 800}; // The initial account balances 6 int[] totalCredits = new int[initialBalance.length]; // Two different cr totals 7 int[] totalDebits = new int[initialBalance.length]; // Two different db totals 8 int transactionCount = 20; // Number of debits and of credits 9 10 // Create the account, the bank, and the clerks... 11 Bank theBank = new Bank(); // Create a bank 12 Clerk clerk1 = new Clerk(theBank); // Create the first clerk 13 Clerk clerk2 = new Clerk(theBank); // Create the second clerk 14 15 // Create the accounts, and initialize total credits and debits 16 Account[] accounts = new Account[initialBalance.length]; 17 for(int i = 0 ; i < initialBalance.length ; ++i) { 18 accounts[i] = new Account(i+1, initialBalance[i]); // Create accounts 19 totalCredits[i] = totalDebits[i] = 0; 20 } 21 // Create the threads for the clerks as daemon, and start them off 22 Thread clerk1Thread = new Thread(clerk1); 23 Thread clerk2Thread = new Thread(clerk2); 24 clerk1Thread.setDaemon(true); // Set first as daemon 25 clerk2Thread.setDaemon(true); // Set second as daemon 26 clerk1Thread.start(); // Start the first 27 clerk2Thread.start(); // Start the second 28 29 // Create transactions randomly distributed between the accounts 30 Random rand = new Random(); 31 Transaction transaction; // Stores a transaction 32 int amount = 0; // Stores an amount of money 33 int select = 0; // Selects an account 34 for(int i = 1; i <= transactionCount; i++) { 35 // Choose an account at random for credit operation 36 select = rand.nextInt(accounts.length); 37 amount = 50 + rand.nextInt(26); // Generate amount of $50 to $75 38 transaction = new Transaction(accounts[select], // Account 39 TransactionType.CREDIT, // Credit transaction 40 amount); // of amount 41 totalCredits[select] += amount; // Keep total credit tally 42 43 // Wait until the first clerk is free 44 while(clerk1.isBusy()) { 45 try { 46 Thread.sleep(25); // Busy so try later 47 } catch(InterruptedException e) { 48 System.out.println(e); 49 } 50 } 51 clerk1.doTransaction(transaction); // Now do the credit 52 53 // choose an account at random for debit operation 54 select = rand.nextInt(accounts.length); 55 amount = 30 + rand.nextInt(31); // Generate amount of $30 to $60 56 transaction = new Transaction(accounts[select], // Account 57 TransactionType.DEBIT, // Debit transaction 58 amount); // of amount 59 totalDebits[select] += amount; // Keep total debit tally 60 61 // Wait until the second clerk is free 62 while(clerk2.isBusy()) { 63 try { 64 Thread.sleep(25); // Busy so try later 65 } catch(InterruptedException e) { 66 System.out.println(e); 67 } 68 } 69 clerk2.doTransaction(transaction); // Now do the debit 70 } 71 72 // Wait until both clerks are done 73 while(clerk1.isBusy() || clerk2.isBusy()) { 74 try { 75 Thread.sleep(25); 76 77 } catch(InterruptedException e) { 78 System.out.println(e); 79 } 80 } 81 82 // Now output the results 83 for(int i = 0; i < accounts.length; ++i) { 84 System.out.println("Account Number:"+accounts[i].getAccountNumber()+" "+ 85 "Original balance : $" + initialBalance[i] + " " + 86 "Total credits : $" + totalCredits[i] + " " + 87 "Total debits : $" + totalDebits[i] + " " + 88 "Final balance : $" + accounts[i].getBalance() + " " + 89 "Should be : $" + (initialBalance[i] 90 + totalCredits[i] 91 - totalDebits[i]) + " "); 92 } 93 } 94 }
synchronized关键字后面圆括号中的表达式用来指定要同步的对象。一旦执行到给定账户对象的同步代码块,就不能再执行为这个账户对象同步的其他代码块或方法。例如,如果用事务的getAccount()方法返回的account[1]对象来引用进行贷款处理的代码块,就不能再执行这个对象的借款处理代码块,但可以执行其他对象的借款处理代码块。