仿真
多线程的优点之一就是仿真:
银行仿真:
package bank;
public class Customer {
private final int serverTime;
public Customer(int serverTime) {
this.serverTime = serverTime;
}
@Override
public String toString() {
return " [serverTime=" + serverTime + "] ";
}
public int getServerTime() {
return serverTime;
}
}
package bank;
import java.util.concurrent.ArrayBlockingQueue;
public class CustomerLine extends ArrayBlockingQueue<Customer> {
public CustomerLine(int size) {
super(size);
}
@Override
public String toString() {
if (this.size() == 0) { // 这里获取 size 是线程安全的
return "CustomerLine []";
}
StringBuilder sb = new StringBuilder();
for (Customer c : this) { // 这里的遍历也是线程安全的
sb.append(c);
}
return sb.toString();
}
}
package bank;
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class CustomerGenerator implements Runnable {
private CustomerLine cl;
private Random random = new Random();
public CustomerGenerator(CustomerLine cl) {
super();
this.cl = cl;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
TimeUnit.MILLISECONDS.sleep(random.nextInt(200));
cl.put(new Customer(random.nextInt(1000)));
}
} catch (InterruptedException ie) {
System.out.println("Generator intrrupt");
}
}
}
package bank;
import java.util.concurrent.TimeUnit;
public class Teller implements Runnable, Comparable<Teller> {
private int servicedNums;
private CustomerLine line;
private static int count = 0;
private final int id = ++count;
private boolean service = true;
public Teller(CustomerLine line) {
super();
this.line = line;
}
@Override
public int compareTo(Teller otherTeller) {
return otherTeller.servicedNums < this.servicedNums ? -1
: (otherTeller.servicedNums > this.servicedNums ? 1 : 0);
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
Customer c = line.take();
TimeUnit.MILLISECONDS.sleep(c.getServerTime());
synchronized (this) {
servicedNums++;
if (!service) {
wait();
}
}
}
} catch (InterruptedException ie) {
System.out.println(this + " interrupt");
}
}
@Override
public String toString() {
return "Teller [id=" + id + "]";
}
public synchronized void doSomeThingElse() {
service = false;
}
public synchronized void serviceTheLine() {
service = true;
notifyAll();
}
}
package bank;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
public class TellerManager implements Runnable {
private PriorityQueue<Teller> workingQueue = new PriorityQueue<>();
private Queue<Teller> doSomeElseQueue = new LinkedList<>();
private int period;
private Random random = new Random();
private CustomerLine line;
private ExecutorService exec;
public TellerManager(int period, CustomerLine line, ExecutorService exec) {
super();
this.period = period;
this.line = line;
this.exec = exec;
Teller teller = new Teller(line);
workingQueue.add(teller);
exec.execute(teller);
}
public void ajustTellerNum() {
if (line.size() / workingQueue.size() > 2) {
if (doSomeElseQueue.size() > 0) {
Teller teller = doSomeElseQueue.remove();
teller.serviceTheLine();
workingQueue.add(teller);
return;// 不用向下执行了
}
Teller teller = new Teller(line);
exec.execute(teller);
workingQueue.add(teller);
return;
}
if (workingQueue.size() > 1 && line.size() / workingQueue.size() < 2) {
removeOneTeller();
}
if (line.size() == 0) {
while (workingQueue.size() > 0) {
removeOneTeller();
}
}
}
private void removeOneTeller() {
Teller teller = workingQueue.poll();
teller.doSomeThingElse();
doSomeElseQueue.offer(teller);
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
TimeUnit.MILLISECONDS.sleep(period);
ajustTellerNum();
System.out.println("{ line: " + line);
StringBuilder sb = new StringBuilder();
for (Teller t : workingQueue) {
sb.append(t);
}
System.out.println("teller: " + sb.toString()+"}");
}
} catch (InterruptedException ie) {
System.out.println("tellermanager intrrupt");
}
}
}
package bank;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class BankTest {
public static void main(String[] args) throws InterruptedException {
CustomerLine line=new CustomerLine(30);
ExecutorService exec=Executors.newCachedThreadPool();
exec.execute(new CustomerGenerator(line));
exec.execute(new Teller(line));
exec.execute(new TellerManager(600, line, exec));
TimeUnit.MILLISECONDS.sleep(6000);
exec.shutdownNow();
}
}
输出结果:
{ line: [serverTime=899] [serverTime=705] [serverTime=227] [serverTime=950]
teller: Teller [id=2]Teller [id=3]}
{ line: [serverTime=227] [serverTime=950] [serverTime=491] [serverTime=320] [serverTime=881] [serverTime=229] [serverTime=737] [serverTime=153]
teller: Teller [id=2]Teller [id=3]Teller [id=4]}
{ line: [serverTime=737] [serverTime=153] [serverTime=593] [serverTime=54] [serverTime=792] [serverTime=860] [serverTime=228] [serverTime=702]
teller: Teller [id=2]Teller [id=3]Teller [id=4]}
{ line: [serverTime=228] [serverTime=702] [serverTime=168] [serverTime=251] [serverTime=62] [serverTime=206] [serverTime=38] [serverTime=715]
teller: Teller [id=2]Teller [id=3]Teller [id=4]}
{ line: [serverTime=62] [serverTime=206] [serverTime=38] [serverTime=715] [serverTime=307] [serverTime=173] [serverTime=758] [serverTime=857] [serverTime=570] [serverTime=657] [serverTime=467] [serverTime=382] [serverTime=35]
teller: Teller [id=2]Teller [id=3]Teller [id=4]Teller [id=5]}
{ line: [serverTime=467] [serverTime=382] [serverTime=35] [serverTime=333] [serverTime=355] [serverTime=996] [serverTime=738]
teller: Teller [id=3]Teller [id=5]Teller [id=4]}
{ line: [serverTime=355] [serverTime=996] [serverTime=738] [serverTime=130] [serverTime=149] [serverTime=448] [serverTime=595] [serverTime=504]
teller: Teller [id=3]Teller [id=5]Teller [id=4]}
{ line: [serverTime=504] [serverTime=876] [serverTime=416] [serverTime=837] [serverTime=563] [serverTime=747] [serverTime=372]
teller: Teller [id=3]Teller [id=5]Teller [id=4]}
{ line: [serverTime=563] [serverTime=747] [serverTime=372] [serverTime=2] [serverTime=160] [serverTime=880] [serverTime=271] [serverTime=571] [serverTime=47]
teller: Teller [id=3]Teller [id=5]Teller [id=4]Teller [id=2]}
Generator intrrupt
Teller [id=2] interrupt
Teller [id=1] interrupt
Teller [id=3] interrupt
tellermanager intrrupt
Teller [id=5] interrupt
Teller [id=4] interrupt