通过工作队列类(WorkQueue)实现的java线程池。WorkQueue类实现线程池的初始化,线程的分配的功能。
本文使用的代码来源于:
1-Java theory and practice: Thread pools and work queues by Brian Goetz
2-《Core Java 8th edition》 Chapter 14. Multithreading 中银行账户间转账的例子
几点说明:
1-wait(),notify(),notifyAll()不属于Thread类,而属于Object类。也就是说所有对象都能使用这些方法。每个对象都有锁。
WorkQueue类:
package ThreadPool;
import java.util.LinkedList;
public class WorkQueue {
private final int nThreads;
private final PoolWorker[] threads;
private final LinkedList queue;
public WorkQueue(int nThreads) {
this.nThreads = nThreads;
queue = new LinkedList();
threads = new PoolWorker[nThreads];
for (int i = 0; i < nThreads; i++) {
threads[i] = new PoolWorker();
threads[i].start();
}
}
public void execute(Runnable r) {
synchronized (queue) {
queue.addLast(r);
queue.notify();
}
}
private class PoolWorker extends Thread {
@Override
public void run() {
Runnable r;
while (true) {
synchronized (queue) {
while (queue.isEmpty()) {
try {
queue.wait();//放弃锁
} catch (InterruptedException ignored) {
}
}
System.out.println("------Thread " + queue.getFirst());
r = (Runnable) queue.removeFirst();
}
// If we don't catch RuntimeException,
// the pool could leak threads
try {
r.run();
} catch (RuntimeException e) {
// You might want to log something here
}
}
}
}
}
Bank类:
package ThreadPool;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* A bank with a number of bank accounts that uses locks for serializing access.
*
* @version 1.30 2004-08-01
* @author Cay Horstmann
*/
public class Bank {
/**
* Constructs the bank.
*
* @param n the number of accounts
* @param initialBalance the initial balance for each account
*/
public Bank(int n, double initialBalance) {
accounts = new double[n];
for (int i = 0; i < accounts.length; i++) {
accounts[i] = initialBalance;
}
bankLock = new ReentrantLock();
sufficientFunds = bankLock.newCondition();
}
/**
* Transfers money from one account to another.
*
* @param from the account to transfer from
* @param to the account to transfer to
* @param amount the amount to transfer
*/
public void transfer(int from, int to, double amount) throws InterruptedException {
bankLock.lock();
try {
while (accounts[from] < amount) {
sufficientFunds.await();
}
System.out.print(Thread.currentThread());
accounts[from] -= amount;
System.out.printf(" %10.2f from %d to %d", amount, from, to);
accounts[to] += amount;
System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
sufficientFunds.signalAll();
} finally {
bankLock.unlock();
}
}
/**
* Gets the sum of all account balances.
*
* @return the total balance
*/
public double getTotalBalance() {
bankLock.lock();
try {
double sum = 0;
for (double a : accounts) {
sum += a;
}
return sum;
} finally {
bankLock.unlock();
}
}
/**
* Gets the number of accounts in the bank.
*
* @return the number of accounts
*/
public int size() {
return accounts.length;
}
private final double[] accounts;
private Lock bankLock;
private Condition sufficientFunds;
}
TransferRunnable类:
package ThreadPool;
/**
* A runnable that transfers money from an account to other accounts in a bank.
*
* @version 1.30 2004-08-01
* @author Cay Horstmann
*/
public class TransferRunnable implements Runnable {
/**
* Constructs a transfer runnable.
*
* @param b the bank between whose account money is transferred
* @param from the account to transfer money from
* @param max the maximum amount of money in each transfer
*/
public TransferRunnable(Bank b, int from, double max) {
bank = b;
fromAccount = from;
maxAmount = max;
}
@Override
public void run() {
try {
// while (true) {
int toAccount = (int) (bank.size() * Math.random());
double amount = maxAmount * Math.random();
bank.transfer(fromAccount, toAccount, amount);
// Thread.sleep((int) (DELAY * Math.random()));
// }
} catch (InterruptedException e) {
}
}
private Bank bank;
private int fromAccount;
private double maxAmount;
private int DELAY = 10;
}
PoolTest类:
package ThreadPool;
import synchBank.Bank;
import synchBank.TransferRunnable;
public class PoolTest {
public static void main(String[] args) {
WorkQueue wQueue = new WorkQueue(5);
Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE);
int i;
for (i = 0; i < NACCOUNTS; i++) {
TransferRunnable r = new TransferRunnable(b, i, INITIAL_BALANCE);
wQueue.execute(r);
}
}
public static final int NACCOUNTS = 100;
public static final double INITIAL_BALANCE = 1000;
}
使用线程池后,线程数量保持在5个。WorkQueue类完成线程的分配和回收。