<<Java 2 入门经典>>(Ivor Horton's Beginning Java 2,JDK5 Edition)
第16章线程
1.继承Thread
import java.io.IOException;
public class TryThread extends Thread {
public TryThread(String firstName, String secondName, long delay) {
this.firstName = firstName; // Store the first name
this.secondName = secondName; // Store the second name
aWhile = delay; // Store the delay
setDaemon(true); // Thread is daemon
}
public static void main(String[] args) {
// Create three threads
Thread first = new TryThread("张 ", "三 ", 200L);
Thread second = new TryThread("李 ", "四 ", 300L);
Thread third = new TryThread("王 ", "五 ", 500L);
System.out.println("Press Enter when you have had enough.../n");
first.start(); // Start the first thread
second.start(); // Start the second thread
//third.setDaemon(false);
third.start(); // Start the third thread
try {
System.in.read(); // Wait until Enter key pressed
System.out.println("Enter pressed.../n");
} catch (IOException e) { // Handle IO exception
System.out.println(e); // Output the exception
}
System.out.println("Ending main()");
return;
}
// Method where thread execution will start
public void run() {
try {
while(true) { // Loop indefinitely...
System.out.print(firstName); // Output first name
sleep(aWhile); // Wait aWhile msec.
System.out.print(secondName + "/n"); // Output second name
}
} catch(InterruptedException e) { // Handle thread interruption
System.out.println(firstName + secondName + e); // Output the exception
}
}
private String firstName; // Store for first name
private String secondName; // Store for second name
private long aWhile; // Delay in milliseconds
}
使用setDaemon(true);设置为守护线程,则当创建它们的纯种结束后守护线程都会灭亡,即main()结束后first,second,third三个Thread
都会死亡。
2.使用Runnable接口
package Ch16;
import java.io.IOException;
public class JumbleNames implements Runnable {
// Constructor
public JumbleNames(String firstName, String secondName, long delay) {
this.firstName = firstName; // Store the first name
this.secondName = secondName; // Store the second name
aWhile = delay; // Store the delay
}
// Method where thread execution will start
public void run() {
try {
while(true) { // Loop indefinitely...
System.out.print(firstName); // Output first name
Thread.sleep(aWhile); // Wait aWhile msec.
System.out.print(secondName+"/n"); // Output second name
}
} catch(InterruptedException e) { // Handle thread interruption
System.out.println(firstName + secondName + e); // Output the exception
}
}
public static void main(String[] args) {
// Create three threads
Thread first = new Thread(new JumbleNames("张 ", "三 ", 200L));
Thread second = new Thread(new JumbleNames("李 ", "四 ", 300L));
Thread third = new Thread(new JumbleNames("王 ", "五 ", 500L));
// Set threads as daemon
first.setDaemon(true);
second.setDaemon(true);
third.setDaemon(true);
System.out.println("Press Enter when you have had enough.../n");
first.start(); // Start the first thread
second.start(); // Start the second thread
third.start(); // Start the third thread
try {
System.in.read(); // Wait until Enter key pressed
System.out.println("Enter pressed.../n");
} catch (IOException e) { // Handle IO exception
System.out.println(e); // Output the exception
}
System.out.println("Ending main()");
return;
}
private String firstName; // Store for first name
private String secondName; // Store for second name
private long aWhile; // Delay in milliseconds
}
3.线程同步 (银行的例子)
使用synchronized声明使方法间互斥,一个类对象的所有同步方法中,一次只能有一个可以执行。
注意这只是控制同一个对象的并发访问,对并行执行同一类的两个不同对象的同步方法并没有控制。
Bank类表示银行计算机
Account类表示帐户
Transaction类表示操作(存或取款)
Clerk表示职员(保存了银行信息和当前业务的细节,各职员独立操作,负责和银行通信来初始化账户的存或取款业务,线程).
//Bank表示银行的计算机,是账户执行操作的代理//
public class Bank {
// Perform a transaction
//public void doTransaction(Transaction transaction) { //会有问题
synchronized public void doTransaction(Transaction transaction) {
int balance = transaction.getAccount().getBalance(); // Get current balance
switch(transaction.getTransactionType()) {
case Transaction.CREDIT:
// Credits require a lot of checks...
try {
Thread.sleep(100);
} catch(InterruptedException e) {
System.out.println(e);
}
balance += transaction.getAmount(); // Increment the balance
break;
case Transaction.DEBIT:
// Debits require even more checks...
try {
Thread.sleep(150);
} catch(InterruptedException e) {
System.out.println(e);
}
balance -= transaction.getAmount(); // Decrement the balance
break;
default: // We should never get here
System.out.println("Invalid transaction");
System.exit(1);
}
transaction.getAccount().setBalance(balance); // Restore the account balance
}
}
Transaction /
public class Transaction {
// Transaction types
public static final int DEBIT = 0;
public static final int CREDIT = 1;
public static String[] types = {"Debit","Credit"};
// Constructor
public Transaction(Account account, int transactionType, int amount) {
this.account = account;
this.transactionType = transactionType;
this.amount = amount;
}
public Account getAccount() {
return account;
}
public int getTransactionType() {
return transactionType;
}
public int getAmount() {
return amount;
}
public String toString() {
return types[transactionType] + " A//C: " + ": $" + amount;
}
private Account account;
private int amount;
private int transactionType;
}
///Account /
public class Account {
// Constructor
public Account(int accountNumber, int balance) {
this.accountNumber = accountNumber; // Set the account number
this.balance = balance; // Set the initial balance
}
// Return the current balance
public int getBalance() {
return balance;
}
// Set the current balance
public void setBalance(int balance) {
this.balance = balance;
}
public int getAccountNumber() {
return accountNumber;
}
public String toString() {
return "A//C No. "+accountNumber+" : $"+balance;
}
private int balance; // The current account balance
private int accountNumber; // Identifies this account
}
//Clerk /
//Clerk表示职员,保存了银行信息和当前业务的细节,各职员独立操作,负责和银行通信来初始化账户的存或取款业务,线程).
public class Clerk implements Runnable {
// Constructor
public Clerk(Bank theBank) {
this.theBank = theBank; // Who the clerk works for
inTray = null; // No transaction initially
}
// Receive a transaction
public void doTransaction(Transaction transaction) {
inTray = transaction;
}
// The working clerk...
public void run() {
while(true) {
while(inTray == null) { // No transaction waiting?
try {
Thread.sleep(150); // Then take a break...
} catch(InterruptedException e) {
System.out.println(e);
}
}
theBank.doTransaction(inTray);
inTray = null; // In-tray is empty
}
}
// Busy check
public boolean isBusy() {
return inTray != null; // A full in-tray means busy!
}
private Bank theBank; // The employer - an electronic marvel
private Transaction inTray; // The in-tray holding a transaction,业务箱
}
//BankOperation
//只有一个帐号,两个职员
import java.util.Random;
public class BankOperation {
public static void main(String[] args) {
int initialBalance = 500; // The initial account balance
int totalCredits = 0; // Total credits on the account
int totalDebits =0; // Total debits on the account
int transactionCount = 20; // Number of debits and credits
// Create the account, the bank, and the clerks...
Bank theBank = new Bank(); // Create a bank
Clerk clerk1 = new Clerk(theBank); // Create the first clerk
Clerk clerk2 = new Clerk(theBank); // Create the second clerk
Account account = new Account(1, initialBalance); // Create an account
// Create the threads for the clerks as daemon, and start them off
Thread clerk1Thread = new Thread(clerk1);
Thread clerk2Thread = new Thread(clerk2);
clerk1Thread.setDaemon(true); // Set first as daemon
clerk2Thread.setDaemon(true); // Set second as daemon
clerk1Thread.start(); // Start the first
clerk2Thread.start(); // Start the second
// Generate transactions of each type and pass to the clerks
Random rand = new Random(); // Random number generator
Transaction transaction; // Stores a transaction
int amount = 0; // stores an amount of money
for(int i = 1; i <= transactionCount; i++) {
amount = 50 + rand.nextInt(26); // Generate amount of $50 to $75
transaction = new Transaction(account, // Account
Transaction.CREDIT,// Credit transaction
amount); // of amount
totalCredits += amount; // Keep total credit tally
// Wait until the first clerk is free
while(clerk1.isBusy()) {
try {
Thread.sleep(25); // Busy so try later
} catch(InterruptedException e) {
System.out.println(e);
}
}
clerk1.doTransaction(transaction); // Now do the credit
amount = 30 + rand.nextInt(31); // Generate amount of $30 to $60
transaction = new Transaction(account, // Account
Transaction.DEBIT, // Debit transaction
amount); // of amount
totalDebits += amount; // Keep total debit tally
// Wait until the second clerk is free
while(clerk2.isBusy()) {
try {
Thread.sleep(25); // Busy so try later
} catch(InterruptedException e) {
System.out.println(e);
}
}
clerk2.doTransaction(transaction); // Now do the debit
}//end for
// Wait until both clerks are done
while(clerk1.isBusy() || clerk2.isBusy()) {
try {
Thread.sleep(25);
} catch(InterruptedException e) {
System.out.println(e);
}
}
// Now output the results
System.out.println(
"Original balance : $" + initialBalance+"/n" +
"Total credits : $" + totalCredits+"/n" +
"Total debits : $" + totalDebits+"/n" +
"Final balance : $" + account.getBalance() + "/n" +
"Should be : $" + (initialBalance + totalCredits - totalDebits));
}
}
/// 两个帐户,两个职员
public class BankOperation {
public static void main(String[] args) {
int[] initialBalance = {500, 800}; // The initial account balances
int[] totalCredits = new int[initialBalance.length]; //Two different cr totals
int[] totalDebits = new int[initialBalance.length]; //Two different db totals
int transactionCount = 20; // Number of debits and credits
// Create the bank and the clerks...
Bank theBank = new Bank(); // Create a bank
Clerk clerk1 = new Clerk(theBank); // Create the first clerk
Clerk clerk2 = new Clerk(theBank); // Create the second clerk
// Create the accounts, and initialize total credits and debits
Account[] accounts = new Account[initialBalance.length];
for(int i = 0; i < initialBalance.length; i++) {
accounts[i] = new Account(i+1, initialBalance[i]); // Create accounts
totalCredits[i] = totalDebits[i] = 0;
}
// Create the threads for the clerks as daemon, and start them off
Thread clerk1Thread = new Thread(clerk1);
Thread clerk2Thread = new Thread(clerk2);
clerk1Thread.setDaemon(true); // Set first as daemon
clerk2Thread.setDaemon(true); // Set second as daemon
clerk1Thread.start(); // Start the first
clerk2Thread.start(); // Start the second
// Create transactions randomly distributed between the accounts
Random rand = new Random();
Transaction transaction; // Stores a transaction
int amount = 0; // Stores an amount of money
int select = 0; // Selects an account
for(int i = 1; i <= transactionCount; i++) {
// Choose an account at random for credit operation
select = rand.nextInt(accounts.length);
amount = 50 + rand.nextInt(26); // Generate amount of $50 to $75
transaction = new Transaction(accounts[select], // Account
Transaction.CREDIT, // Credit transaction
amount); // of amount
totalCredits[select] += amount; // Keep total credit tally
// Wait until the first clerk is free
while(clerk1.isBusy()) {
try {
Thread.sleep(25); // Busy so try later
} catch(InterruptedException e) {
System.out.println(e);
}
}
clerk1.doTransaction(transaction); // Now do the credit
// choose an account at random for debit operation
select = rand.nextInt(accounts.length);
amount = 30 + rand.nextInt(31); // Generate amount of $30 to $60
transaction = new Transaction(accounts[select], // Account
Transaction.DEBIT, // Debit transaction
amount); // of amount
totalDebits[select] += amount; // Keep total debit tally
// Wait until the second clerk is free
while(clerk2.isBusy()) {
try {
Thread.sleep(25); // Busy so try later
} catch(InterruptedException e) {
System.out.println(e);
}
}
clerk2.doTransaction(transaction); // Now do the debit
}
// Wait until both clerks are done
while(clerk1.isBusy() || clerk2.isBusy()) {
try {
Thread.sleep(25);
} catch(InterruptedException e) {
System.out.println(e);
}
}
// Now output the results
for(int i = 0; i < accounts.length; i++) {
System.out.println("Account Number:"+accounts[i].getAccountNumber()+"/n"+
"Original balance : $" + initialBalance[i] + "/n" +
"Total credits : $" + totalCredits[i] + "/n" +
"Total debits : $" + totalDebits[i] + "/n" +
"Final balance : $" + accounts[i].getBalance() + "/n" +
"Should be : $" + (initialBalance[i]
+ totalCredits[i]
- totalDebits[i]) + "/n");
}
}
}
///类Bank声明为synchronized严重限制了程序。如果一种操作在进行则其他的操作都不能进行,
//实际上,一个账户在进行业务时,不该阻止另一个账户上的业务操作,对Bank进行修改
synchronized(transaction.getAccount()) {
System.out.println("Start credit of " +
transaction.getAccount() + " amount: " +
transaction.getAmount());
// Get current balance
int balance = transaction.getAccount().getBalance();
....
balance += transaction.getAmount(); // Increment the balance
....
transaction.getAccount().setBalance(balance); // Restore the account balance
break;
}