使用線程、線程池解析經典的「信用卡帳戶存取款問題」

step_01:定義一個信用卡帳戶類CreditCard.java
package com.panny.thread;

public class CreditCard {

	private String cid; // 信用卡帳戶
	private int balance; // 信用卡餘額
	
	public CreditCard(String cid, int balance) {
		this.cid = cid;
		this.balance = balance;
	}

	public String getCid() {
		return cid;
	}

	public void setCid(String cid) {
		this.cid = cid;
	}

	public int getBalance() {
		return balance;
	}

	public void setBalance(int balance) {
		this.balance = balance;
	}
	
	public String toString() {
		return "{" + this.cid + "}";
	}
	
}

step_02:定義一個線程安全的操做類SafeOperation.java java

package com.panny.thread;

import java.util.concurrent.locks.ReadWriteLock;

public class SafeOperation implements Runnable {

	private String atm; // 執行操做的取款機名稱
	private CreditCard myCard; // 執行操做的信用卡
	private int ioCash; // 操做的金額
	private ReadWriteLock lock; // 執行操做的對象鎖,此處爲讀寫鎖
	private int operationType; // 操做類型:存款-1, 取款-2, 查詢-3

	public SafeOperation(String atm, CreditCard myCard, int ioCash, ReadWriteLock lock, int operationType) {
		this.atm = atm;
		this.myCard = myCard;
		this.ioCash = ioCash;
		this.lock = lock;
		this.operationType = operationType;
	}
	
	@Override
	public void run() {
		// 根據操做類型執行動做
		if(this.operationType == 1) { // 存款
			makeLock(1); // 打開寫入鎖(必須)
			
			System.out.println("ATM: " + this.atm + "\n" +
				           "CID: " + this.myCard.toString() + "\n" +
					   "TyPE: input" + "\n" +
					   "CURRENT_BALANCE: " + this.myCard.getBalance()+"\n" +
					   "INPUT CASH: " + this.ioCash);
			
			try {
				System.out.println("Doing...");
				int currBalance = this.myCard.getBalance();
				this.myCard.setBalance(currBalance + this.ioCash);
				Thread.sleep(2000);
				System.out.println("SUCCESS!! ATM: " + this.atm + "\n" +
						   "CID: " + this.myCard.toString() + "\n" +
						   "CURRENT_BALANCE: " + this.myCard.getBalance() + "\n");
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				unlock(1); // 關閉寫入鎖(必須)
			}			
		} else if(this.operationType == 2) {
			makeLock(1);
			
			System.out.println("ATM: " + this.atm + "\n" +
					   "CID: " + this.myCard.toString() + "\n" +
					   "TyPE: output" + "\n" +
					   "CURRENT_BALANCE: " + this.myCard.getBalance()+"\n" +
					   "INPUT CASH: " + this.ioCash);
			
			try {
				System.out.println("Doing...");
				int currBalance = this.myCard.getBalance();
				this.myCard.setBalance(currBalance - this.ioCash);
				Thread.sleep(2000);
				System.out.println("SUCCESS!! ATM: " + this.atm + "\n" +
						   "CID: " + this.myCard.toString() + "\n" +
						   "CURRENT_BALANCE: " + this.myCard.getBalance() + "\n");
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				unlock(1);
			}
		} else if(this.operationType == 3) {
			makeLock(2);
			
			try {
				System.out.println("Doing...");
				Thread.sleep(2000);
				System.out.println("ATM: " + this.atm + "\n" +
						   "CID: " + this.myCard.toString() + "\n" +
						   "TyPE: query" + "\n" +
						   "CURRENT_BALANCE: " + this.myCard.getBalance() + "\n");
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				unlock(2);
			}
		}
	}
	
	/**
	 * 根據參數類型執行打開寫入鎖(type=1),或打開讀取鎖(type=2)
	 * @param type
	 */
	private void makeLock(int type) {
		switch(type) {
		case 1:
			this.lock.writeLock().lock();
			break;
		case 2:
			this.lock.readLock().lock();
			break;
		}
	}
	
	/**
	 * 根據參數類型執行關閉寫入鎖(type=1),或關閉讀取鎖(type=2)
	 * @param type
	 */
	private void unlock(int type) {
		switch(type) {
		case 1:
			this.lock.writeLock().unlock();
			break;
		case 2:
			this.lock.readLock().unlock();
			break;
		}
	}

}
step_03:定義一個測試類 CreditCardTest.java
package com.panny.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class CreditCardTest {

	public static void main(String[] args) {
		
		CreditCard card = new CreditCard("000-111-222", 5000);
		
		ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); //--------1
		
		ExecutorService pool = Executors.newCachedThreadPool(); //------------2
		
		SafeOperation operation1 = new SafeOperation("ATM001", card, 200, lock, 1);
		SafeOperation operation2 = new SafeOperation("ATM002", card, 300, lock, 2);
		SafeOperation operation3 = new SafeOperation("ATM003", card, 500, lock, 3);
		SafeOperation operation4 = new SafeOperation("ATM004", card, 100, lock, 1);
		
		pool.execute(operation1);
		pool.execute(operation2);
		pool.execute(operation3);
		pool.execute(operation4);
		
		pool.shutdown(); //-----------3
		
		
	}

}
//---------1:

若是能夠明確區分讀/寫操做,那麼,建議使用讀/寫鎖來提升性能,
否則使用普通鎖:java.util.concurrent.locks.Lock和它的直接子類:ReentrantLock
//--------2:
java.util.concurrent.Executors:
建立一個線程池,根據須要建立新線程,但當他們是可用的時候,將重用先前構造的線程
//--------3:
記得關閉線程池是個好習慣
安全

相關文章
相關標籤/搜索