51.对象序列化的具体应用
这也是书里的一个例子,挺有意思的。结合模板方法模式模拟CAD将用户作业的信息保存在文件中:
import java.io.*;
import java.util.*;
abstract class Shape implements Serializable{
public static final int RED=1,BLUE=2,GREEN=3;
private int xPos,yPos,dimension;
private static Random rand=new Random(47);
private static int counter=0;
public abstract void setColor(int newColor);
public abstract int getColor();
public Shape(int xVal,int yVal,int dim){
xPos=xVal;
yPos=yVal;
dimension=dim;
}
public String toString(){
return getClass()+
": color["+getColor()+"] xpos["+xPos+
"] yPos["+yPos+"] dim["+dimension+"]\n";
}
public static Shape randomFactory(){
int xVal=rand.nextInt(100);
int yVal=rand.nextInt(100);
int dim=rand.nextInt(100);
switch(counter++%3){
default:
case 0: return new Circle(xVal,yVal,dim);
case 1: return new Square(xVal,yVal,dim);
case 2: return new Line(xVal,yVal,dim);
}
}
}
class Circle extends Shape{
private static int color=RED;
public Circle(int xVal,int yVal,int dim){
super(xVal,yVal,dim);
}
public void setColor(int newColor){color=newColor;}
public int getColor(){return color;}
}
class Square extends Shape{
private static int color;
public Square(int xVal,int yVal,int dim){
super(xVal,yVal,dim);
color=RED;
}
public void setColor(int newColor){color=newColor;}
public int getColor(){return color;}
}
class Line extends Shape{
private static int color=RED;
public static void serializeStaticState(ObjectOutputStream os)
throws IOException{os.writeInt(color);}
public static void deserializeStaticState(ObjectInputStream os)
throws IOException{color=os.readInt();}
public Line(int xVal,int yVal,int dim){
super(xVal,yVal,dim);
}
public void setColor(int newColor){color=newColor;}
public int getColor(){return color;}
}
public class StoreCADState{
public static void main(String[] args) throws Exception{
List> shapeTypes=
new ArrayList>();
shapeTypes.add(Circle.class);
shapeTypes.add(Square.class);
shapeTypes.add(Line.class);
List shapes=new ArrayList();
for(int i=0;i<10;i++)
shapes.add(Shape.randomFactory());
for(int i=0;i<10;i++)
((Shape)shapes.get(i)).setColor(Shape.GREEN);
ObjectOutputStream out=new ObjectOutputStream(
new FileOutputStream("CADState.out"));
out.writeObject(shapeTypes);
Line.serializeStaticState(out);
out.writeObject(shapes);
System.out.println(shapes);
}
}/*Output
[class Circle: color[3] xpos[58] yPos[55] dim[93]
, class Square: color[3] xpos[61] yPos[61] dim[29]
, class Line: color[3] xpos[68] yPos[0] dim[22]
, class Circle: color[3] xpos[7] yPos[88] dim[28]
, class Square: color[3] xpos[51] yPos[89] dim[9]
, class Line: color[3] xpos[78] yPos[98] dim[61]
, class Circle: color[3] xpos[20] yPos[58] dim[16]
, class Square: color[3] xpos[40] yPos[11] dim[22]
, class Line: color[3] xpos[4] yPos[83] dim[6]
, class Circle: color[3] xpos[75] yPos[10] dim[42]
]
*///~
52.读取当前目录文件列表
利用FilenameFilter接口和正则读取文件列表,有普通面向对象方法,也可以写成普通内部类和匿名内部类:
1).一般面向对象
import java.io.*;
import java.util.*;
import java.util.regex.*;
public class DirList{
public static void main(String[] args){
File path=new File(".");
String[] list;
if(args.length==0)
list=path.list();
else
list=path.list(new DirFilter(args[0]));
Arrays.sort(list,String.CASE_INSENSITIVE_ORDER);
for(String dirItem:list)
System.out.println(dirItem);
}
}
class DirFilter implements FilenameFilter{
private Pattern pattern;
public DirFilter(String regex){
pattern=Pattern.compile(regex);
}
public boolean accept(File dir,String name){
return pattern.matcher(name).matches();
}
}/*Output
Waterproof.class
WhoCalled.class
WhoCalled.java
Wind.class
Window.class
Woodwind.class
*///~
2).匿名内部类
import java.util.*;
import java.util.regex.*;
import java.io.*;
public class DirList2{
public static FilenameFilter filter(final String regex){
return new FilenameFilter(){
private Pattern pattern=Pattern.compile(regex);
public boolean accept(File dir,String name){
return pattern.matcher(name).matches();
}
};
}
public static void main(String[] args){
File path=new File(".");
String[] list;
if(args.length==0)
list=path.list();
else
list=path.list(filter(args[0]));
Arrays.sort(list,String.CASE_INSENSITIVE_ORDER);
for(String dirItem : list)
System.out.println(dirItem);
}
}/*Output
WhoCalled.class
WhoCalled.java
Wind.class
Window.class
Woodwind.class
Zi.class
*///~
3).普通内部类
import java.io.*;
import java.util.*;
import java.util.regex.*;
public class DirList3{
public static void main(final String[] args){
File path=new File(".");
String[] list;
if(args.length==0)
list=path.list();
else
list=path.list(new FilenameFilter(){
private Pattern pattern=Pattern.compile(args[0]);
public boolean accept(File dir,String name){
return pattern.matcher(name).matches();
}
});
Arrays.sort(list,String.CASE_INSENSITIVE_ORDER);
for(String dirItem:list)
System.out.println(dirItem);
}
}/*Output
WhoCalled.class
WhoCalled.java
Wind.class
Window.class
Woodwind.class
Zi.class
*///~
53.枚举
java的枚举只是一个小特性,但是功能强悍。枚举是特殊的类,可以有自己的构造方法(必须是private),普通方法,变量(默认为static+final)。
这里有个剪刀石头布的游戏:
1).先看看传统的方法怎么解决:
import java.util.*;
enum Outcome{WIN,LOSE,DRAW}
interface Item{
Outcome compete(Item it);
Outcome eval(Paper p);
Outcome eval(Scissors s);
Outcome eval(Rock r);
}
class Paper implements Item{
public Outcome compete(Item it){return it.eval(this); }
public Outcome eval(Paper p){return Outcome.DRAW;}
public Outcome eval(Scissors s){return Outcome.WIN;}
public Outcome eval(Rock r){return Outcome.LOSE;}
public String toString(){return "Paper";}
}
class Scissors implements Item{
public Outcome compete(Item it){return it.eval(this); }
public Outcome eval(Paper p){return Outcome.LOSE;}
public Outcome eval(Scissors s){return Outcome.DRAW;}
public Outcome eval(Rock r){return Outcome.WIN;}
public String toString(){return "Scissors";}
}
class Rock implements Item{
public Outcome compete(Item it){return it.eval(this); }
public Outcome eval(Paper p){return Outcome.WIN;}
public Outcome eval(Scissors s){return Outcome.LOSE;}
public Outcome eval(Rock r){return Outcome.DRAW;}
public String toString(){return "Rock";}
}
public class RoShamBo1{
static final int SIZE=20;
private static Random rand=new Random(47);
public static Item newItem(){
switch(rand.nextInt(3)){
default:
case 0:return new Scissors();
case 1:return new Paper();
case 2:return new Rock();
}
}
public static void match(Item a,Item b){
System.out.println(a+" vs. "+b+": "+a.compete(b));
}
public static void main(String[] args){
for(int i=0;i/*Output
Rock vs. Rock: DRAW
Paper vs. Rock: WIN
Paper vs. Rock: WIN
Paper vs. Rock: WIN
Scissors vs. Paper: WIN
Scissors vs. Scissors: DRAW
Scissors vs. Paper: WIN
Rock vs. Paper: LOSE
Paper vs. Paper: DRAW
Rock vs. Paper: LOSE
Paper vs. Scissors: LOSE
Paper vs. Scissors: LOSE
Rock vs. Scissors: WIN
Rock vs. Paper: LOSE
Paper vs. Rock: WIN
Scissors vs. Paper: WIN
Paper vs. Scissors: LOSE
Paper vs. Scissors: LOSE
Paper vs. Scissors: LOSE
Paper vs. Scissors: LOSE
*///~
2).使用枚举的方法,整体的代码比传统方法少:
import java.util.*;
interface Competitor>{
Outcome compete(T competitor);
}
enum Outcome{WIN,LOSE,DRAW}
class Enums{
private static Random rand=new Random(47);
public static > T random(Class ec){
return random(ec.getEnumConstants());
}
private static T random(T[] values){
return values[rand.nextInt(values.length)];
}
}
class RoShamBo{
public static > void match(T a,T b){
System.out.println(a+" vs "+b+" : "+a.compete(b));
}
public static & Competitor>
void play(Class rsbClass,int size){
for(int i=0;ipublic enum RoShamBo3 implements Competitor{
PAPER{
public Outcome compete(RoShamBo3 it){
switch(it){
default:
case PAPER:return Outcome.DRAW;
case SCISSORS:return Outcome.LOSE;
case ROCK:return Outcome.WIN;
}
}
},
SCISSORS{
public Outcome compete(RoShamBo3 it){
switch(it){
default:
case PAPER:return Outcome.WIN;
case SCISSORS:return Outcome.DRAW;
case ROCK:return Outcome.LOSE;
}
}
},
ROCK{
public Outcome compete(RoShamBo3 it){
switch(it){
default:
case PAPER:return Outcome.LOSE;
case SCISSORS:return Outcome.WIN;
case ROCK:return Outcome.DRAW;
}
}
};
public abstract Outcome compete(RoShamBo3 it);
public static void main(String[] args){
RoShamBo.play(RoShamBo3.class,20);
}
}/*Output
ROCK vs ROCK : DRAW
SCISSORS vs ROCK : LOSE
SCISSORS vs ROCK : LOSE
SCISSORS vs ROCK : LOSE
PAPER vs SCISSORS : LOSE
PAPER vs PAPER : DRAW
PAPER vs SCISSORS : LOSE
ROCK vs SCISSORS : WIN
SCISSORS vs SCISSORS : DRAW
ROCK vs SCISSORS : WIN
SCISSORS vs PAPER : WIN
SCISSORS vs PAPER : WIN
ROCK vs PAPER : LOSE
ROCK vs SCISSORS : WIN
SCISSORS vs ROCK : LOSE
PAPER vs SCISSORS : LOSE
SCISSORS vs PAPER : WIN
SCISSORS vs PAPER : WIN
SCISSORS vs PAPER : WIN
SCISSORS vs PAPER : WIN
*///~
3).使用枚举的Map集合:EnumMap的速度性能比其他Map都强得多,因为枚举都是static的,但是如果Map过大,又会占用更多的内存空间(计算机世界中,时间空间是一对矛盾)
import java.util.*;
enum Outcome{WIN,LOSE,DRAW}
class RoShamBo{
public static > void match(T a,T b){
System.out.println(a+" vs "+b+" : "+a.compete(b));
}
public static & Competitor>
void play(Class rsbClass,int size){
for(int i=0;ienum RoShamBo5 implements Competitor{
PAPER,SCISSORS,ROCK;
static EnumMap> table =
new EnumMap>(RoShamBo5.class);
static{
for(RoShamBo5 it:RoShamBo5.values())
table.put(it,new EnumMap(RoShamBo5.class));
initRow(PAPER,Outcome.DRAW,Outcome.LOSE,Outcome.WIN);
initRow(SCISSORS,Outcome.WIN,Outcome.DRAW,Outcome.LOSE);
initRow(ROCK,Outcome.LOSE,Outcome.WIN,Outcome.DRAW);
}
static void initRow(RoShamBo5 it,
Outcome vPAPER,Outcome vSCISSORS,Outcome vROCK){
EnumMap row=RoShamBo5.table.get(it);
row.put(RoShamBo5.PAPER,vPAPER);
row.put(RoShamBo5.SCISSORS,vSCISSORS);
row.put(RoShamBo5.ROCK,vROCK);
}
public Outcome compete(RoShamBo5 it){
return table.get(this).get(it);
}
public static void main(String[] args){
RoShamBo.play(RoShamBo5.class,20);
}
}/*Output
ROCK vs ROCK : DRAW
SCISSORS vs ROCK : LOSE
SCISSORS vs ROCK : LOSE
SCISSORS vs ROCK : LOSE
PAPER vs SCISSORS : LOSE
PAPER vs PAPER : DRAW
PAPER vs SCISSORS : LOSE
ROCK vs SCISSORS : WIN
SCISSORS vs SCISSORS : DRAW
ROCK vs SCISSORS : WIN
SCISSORS vs PAPER : WIN
SCISSORS vs PAPER : WIN
ROCK vs PAPER : LOSE
ROCK vs SCISSORS : WIN
SCISSORS vs ROCK : LOSE
PAPER vs SCISSORS : LOSE
SCISSORS vs PAPER : WIN
SCISSORS vs PAPER : WIN
SCISSORS vs PAPER : WIN
SCISSORS vs PAPER : WIN
*///~
54.枚举应用在命令行模式中
命令行模式是把接口当成一个参数传进给方法,该方法去动态地实现接口的方法,增强程序的拓展性。
import java.util.*;
enum AlarmPoints{
STAIR1,STAIR2,LOBBY,OFFICE1,OFFICE2,OFFICE3,
OFFICE4,BATHROOM,UTILITY,KITCHEN
}
interface Command{void action();}
public class EnumMaps{
public static void main(String[] args){
EnumMap em=
new EnumMap(AlarmPoints.class);
em.put(AlarmPoints.KITCHEN,new Command(){
public void action(){System.out.println("Kitchen fire!");}});
em.put(AlarmPoints.BATHROOM,new Command(){
public void action(){System.out.println("Bathroom alert!");}});
for(Map.Entry e : em.entrySet()){
System.out.print(e.getKey()+": ");
e.getValue().action();
}
try{
em.get(AlarmPoints.UTILITY).action();
}catch(Exception e){
System.out.println(e);
}
}
}/*Output
BATHROOM: Bathroom alert!
KITCHEN: Kitchen fire!
java.lang.NullPointerException
*///~
55.枚举应用在责任链模式中
责任链模式是把解决问题的几种方案串联起来,增强程序可读性、健壮性。下面的例子以邮局处理信件为例,处理一封邮件需要先知道送信路线、扫描信件、邮件可读判断、检查地址、确认地址。没一个环节都好几个解决方案,比如送信路线就有好多条,其它也如此。而且各环节是串联成一条线的。仿佛程序就跟日常生活一样。
import java.util.*;
class Enums{
private static Random rand=new Random(47);
public static > T random(Class ec){
return random(ec.getEnumConstants());
}
private static T random(T[] values){
return values[rand.nextInt(values.length)];
}
}
class Mail{
enum GeneralDelivery{YES,NO1,NO2,NO3,NO4,NO5}
enum Scannability{UNSCANNABLE,YES1,YES2,YES3,YES4}
enum Readability{ILLEGIBLE,YES1,YES2,YES3,YES4}
enum Address{INCORRECT,OK1,OK2,OK3,OK4,OK5,OK6}
enum ReturnAddress{MISSING,OK1,OK2,OK3,OK4,OK5}
GeneralDelivery generalDelivery;
Scannability scannability;
Readability readability;
Address address;
ReturnAddress returnAddress;
static long counter=0;
long id=counter++;
public String toString(){return "Mail "+id;}
public String details(){
return toString()+
", General Delivery: "+ generalDelivery+
", Address Scanability: "+scannability+
", Address Readability: "+readability+
", Address Address: "+address+
", Return address: "+returnAddress;
}
public static Mail randomMail(){
Mail m=new Mail();
m.generalDelivery=Enums.random(GeneralDelivery.class);
m.scannability=Enums.random(Scannability.class);
m.readability=Enums.random(Readability.class);
m.address=Enums.random(Address.class);
m.returnAddress=Enums.random(ReturnAddress.class);
return m;
}
public static Iterable generator(final int count){
return new Iterable(){
int n=count;
public Iterator iterator(){
return new Iterator(){
public boolean hasNext(){return n-- > 0;}
public Mail next(){return randomMail();}
public void remove(){throw new UnsupportedOperationException();}
};
}
};
}
}
public class PostOffice{
enum MailHandler{
GENERAL_DELIVERY{
boolean handle(Mail m){
switch(m.generalDelivery){
case YES:
System.out.println("Using general delivery for "+m);
return true;
default: return false;
}
}
},
MACHINE_SCAN{
boolean handle(Mail m){
switch(m.scannability){
case UNSCANNABLE:return false;
default:
switch(m.address){
case INCORRECT:return false;
default:
System.out.println("Delivering "+m+" automatically");
return true;
}
}
}
},
VISUAL_INSPECTION{
boolean handle(Mail m){
switch(m.readability){
case ILLEGIBLE:return false;
default:
switch(m.address){
case INCORRECT: return false;
default:
System.out.println("Delivering "+m+" normally");
return true;
}
}
}
},
RETURN_TO_SENDER{
boolean handle(Mail m){
switch(m.returnAddress){
case MISSING:return false;
default:
System.out.println("Returning "+m+" to sender");
return true;
}
}
};
abstract boolean handle(Mail m);
}
static void handle(Mail m){
for(MailHandler handler : MailHandler.values())
if(handler.handle(m))
return;
System.out.println(m+" is a dead letter");
}
public static void main(String[] args){
for(Mail mail:Mail.generator(10)){
System.out.println(mail.details());
handle(mail);
System.out.println("*************");
}
}
}/*Output
Mail 0, General Delivery: NO2, Address Scanability: UNSCANNABLE, Address Readability: YES3, Address Address: OK1, Return address: OK1
Delivering Mail 0 normally
*************
Mail 1, General Delivery: NO5, Address Scanability: YES3, Address Readability: ILLEGIBLE, Address Address: OK5, Return address: OK1
Delivering Mail 1 automatically
*************
Mail 2, General Delivery: YES, Address Scanability: YES3, Address Readability: YES1, Address Address: OK1, Return address: OK5
Using general delivery for Mail 2
*************
Mail 3, General Delivery: NO4, Address Scanability: YES3, Address Readability: YES1, Address Address: INCORRECT, Return address: OK4
Returning Mail 3 to sender
*************
Mail 4, General Delivery: NO4, Address Scanability: UNSCANNABLE, Address Readability: YES1, Address Address: INCORRECT, Return address: OK2
Returning Mail 4 to sender
*************
Mail 5, General Delivery: NO3, Address Scanability: YES1, Address Readability: ILLEGIBLE, Address Address: OK4, Return address: OK2
Delivering Mail 5 automatically
*************
Mail 6, General Delivery: YES, Address Scanability: YES4, Address Readability: ILLEGIBLE, Address Address: OK4, Return address: OK4
Using general delivery for Mail 6
*************
Mail 7, General Delivery: YES, Address Scanability: YES3, Address Readability: YES4, Address Address: OK2, Return address: MISSING
Using general delivery for Mail 7
*************
Mail 8, General Delivery: NO3, Address Scanability: YES1, Address Readability: YES3, Address Address: INCORRECT, Return address: MISSING
Mail 8 is a dead letter
*************
Mail 9, General Delivery: NO1, Address Scanability: UNSCANNABLE, Address Readability: YES2, Address Address: OK1, Return address: OK4
Delivering Mail 9 normally
*************
*///~
56.线程的重要性
书上的原话:”if someone implies that threading is easy and straightforward, make sure that person is not making important decisions about your project, if that person already is, then you’ve got trouble. “
如果一个人觉得线程是容易和直接的,那么确保不要让这个人在你的项目中重要的决策,如果这个人已经是,你会有麻烦的。
作者在章节的总结说线程是编程语言的”black art(黑色的艺术)”。而且,线程的篇幅是也是 Thinking in Java 中最多的,也是最难懂的。
57.基本Java多线程
java本身是多线程的,多线程的目地也是为了提高性能,尽最大可能利用CPU,线程本身只是个载体,运载执行任务的载体。多线程可以理解为每个线程都是独立的,互不干扰,同步分工工作。
在语法中,常见的是实现Runnable接口和继承Thread,传入Thread中的对象也要先实现Runnable接口。也可以使用 Executors 批量执行线程,常见的有CachedThreadPools, FixedThreadPools.推荐使用灵活性较高的CachedThreadPools。线程的状态有 new(初始化),blocked(阻塞),runnable(可运行),dead(死亡),如果处在blocked(可能是sleep(不释放持有对象的锁)或wait(释放持有对象的锁)),可以通过 notifyAll()或notify()唤醒,推荐使用notifyAll()。
58.线程优先级
线程的优先级并不是指一定先执行哪个,而是指线程被先执行的概率,比如:MAX_PRIORITY, NORM_PRIORIRT, MIN_PRIORITY 的概率分别是 10 5 1。
59.synchronized的灵活使用
在解决共享资源问题中,synchronized是常用的方法,当多个线程执行被syncchronized修饰的代码时,一个线程进去了,其他线程须等待,只需要一个synchronized便可。但是,synchronized的开销比较大,造成线程等待时间过长,影响性能,和 Lock,Atomic 相比较,synchronized的使用有两种情况:
1).需要同步的代码快比较小;
2).synchronized的可读性相对Lock,Atomic好;
在使用synchronized也要注意尽可能使被修饰的代码块小,下面的例子比较synchronized修饰一个方法和方法内部的部分代码的性能,可以看出,把创建对象等一些不需要同步的操作放在synchronized外,有助于提高性能:
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.*;
class Pair{
private int x,y;
public Pair(int x,int y){
this.x=x;
this.y=y;
}
public Pair(){this(0,0);}
public int getX(){return x;}
public int getY(){return y;}
public void incrementX(){x++;}
public void incrementY(){y++;}
public String toString(){
return "x: "+x+" ,y: "+y;
}
public class PairValuesNotEqualException
extends RuntimeException{
public PairValuesNotEqualException(){
super("Pair values not equal: "+Pair.this);
}
}
public void checkState(){
if(x!=y)
throw new PairValuesNotEqualException();
}
}
abstract class PairManager{
AtomicInteger checkCounter=new AtomicInteger(0);
protected Pair p=new Pair();
private List storage=
Collections.synchronizedList(new ArrayList());
public synchronized Pair getPair(){
return new Pair(p.getX(),p.getY());
}
protected void store(Pair p){
storage.add(p);
try{
TimeUnit.MILLISECONDS.sleep(50);
}catch(InterruptedException e){}
}
public abstract void increment();
}
class PairManager1 extends PairManager{
public synchronized void increment(){
p.incrementX();
p.incrementY();
store(getPair());
}
}
class PairManager2 extends PairManager{
public void increment(){
Pair temp;
synchronized(this){
p.incrementX();
p.incrementY();
temp=getPair();
}
store(temp);
}
}
class PairManipulator implements Runnable{
private PairManager pm;
public PairManipulator(PairManager pm){
this.pm=pm;
}
public void run(){
while(true){
pm.increment();
}
}
public String toString(){
return "Pair: "+pm.getPair()+
" checkCounter = "+pm.checkCounter.get();
}
}
class PairChecker implements Runnable{
private PairManager pm;
public PairChecker(PairManager pm){
this.pm=pm;
}
public void run(){
while(true){
pm.checkCounter.incrementAndGet();
pm.getPair().checkState();
}
}
}
public class CriticalSection{
static void
testApproaches(PairManager pman1,PairManager pman2){
ExecutorService exec=Executors.newCachedThreadPool();
PairManipulator
pm1=new PairManipulator(pman1),
pm2=new PairManipulator(pman2);
PairChecker
pcheck1=new PairChecker(pman1),
pcheck2=new PairChecker(pman2);
exec.execute(pm1);
exec.execute(pm2);
exec.execute(pcheck1);
exec.execute(pcheck2);
try{
TimeUnit.MILLISECONDS.sleep(500);
}catch(InterruptedException e){
System.out.println("sleep interrupted");
}
System.out.println("pm1: "+pm1+"\npm2: "+pm2);
System.exit(0);
}
public static void main(String[] args){
PairManager
pman1=new PairManager1(),
pman2=new PairManager2();
testApproaches(pman1,pman2);
}
}/*Output
pm1: Pair: x: 102 ,y: 102 checkCounter = 70702
pm2: Pair: x: 103 ,y: 103 checkCounter = 119797967
*///~
60.线程合作
–生产消费关系
比如一个餐厅,每位客人在等待食物,而厨师只有一个,他只能每一时刻为一个客人准备食物,把客人看成线程,厨师看成线程,厨师做好了,客人才能执行吃饭(厨师线程执行完成前,客人线程不能执行),同时,厨师是一份一份得做(厨师是共享资源),客人得等待排队。
看例子:
import java.util.concurrent.*;
class Meal{
private final int orderNum;
public Meal(int orderNum){this.orderNum=orderNum;}
public String toString(){return "Meal "+orderNum;}
}
class WaitPerson implements Runnable{
private Restaurant restaurant;
public WaitPerson(Restaurant r){restaurant=r;}
public void run(){
try{
while(!Thread.interrupted()){
synchronized(this){
while(restaurant.meal==null)
wait();
}
System.out.println("WaitPeron got "+restaurant.meal);
synchronized(restaurant.chef){
restaurant.meal=null;
restaurant.chef.notifyAll();
}
}
}catch(InterruptedException e){
System.out.println("WaitPerson interrupted");
}
}
}
class Chef implements Runnable{
private Restaurant restaurant;
private int count=0;
public Chef(Restaurant r){restaurant=r;}
public void run(){
try{
while(!Thread.interrupted()){
synchronized(this){
while(restaurant.meal!=null)
wait();
}
if(++count==10){
System.out.println("Out of food, closing");
restaurant.exec.shutdownNow();
}
System.out.print("Order up!");
synchronized(restaurant.waitPerson){
restaurant.meal=new Meal(count);
restaurant.waitPerson.notifyAll();
}
TimeUnit.MILLISECONDS.sleep(100);
}
}catch(InterruptedException e){
System.out.println("Chef interrupted");
}
}
}
public class Restaurant{
Meal meal;
ExecutorService exec=Executors.newCachedThreadPool();
WaitPerson waitPerson=new WaitPerson(this);
Chef chef=new Chef(this);
public Restaurant(){
exec.execute(chef);
exec.execute(waitPerson);
}
public static void main(String[] args){
new Restaurant();
}
}/*Output
Order up!WaitPeron got Meal 1
Order up!WaitPeron got Meal 2
Order up!WaitPeron got Meal 3
Order up!WaitPeron got Meal 4
Order up!WaitPeron got Meal 5
Order up!WaitPeron got Meal 6
Order up!WaitPeron got Meal 7
Order up!WaitPeron got Meal 8
Order up!WaitPeron got Meal 9
Out of food, closing
Order up!WaitPerson interrupted
Chef interrupted
*///~
–装饰关系
除了上面普通的方法,还可以利用队列来实现,在java.util.concurrent 中有个BlockingQueue,这里采用LinkedBlockingQueue。新的需求是:把15个干面包线程放在一个队列中,依次给每个干面包涂上黄油:
import java.util.*;
import java.util.concurrent.*;
class Toast{
public enum Status{DRY,BUTTERED,JAMMED}
private Status status=Status.DRY;
private final int id;
public Toast(int idn){id=idn;}
public void butter(){status=Status.BUTTERED;}
public void jam(){status=Status.JAMMED;}
public Status getStatus(){return status;}
public int getId(){return id;}
public String toString(){
return "Toast "+id+": "+status;
}
}
class ToastQueue extends LinkedBlockingQueue<Toast>{}
class Toaster implements Runnable{
private ToastQueue toastQueue;
private int count=0;
private Random rand=new Random(47);
public Toaster(ToastQueue tq){toastQueue=tq;}
public void run(){
try{
while(!Thread.interrupted()){
TimeUnit.MILLISECONDS.sleep(100+rand.nextInt(500));
Toast t=new Toast(count++);
System.out.println(t);
toastQueue.put(t);
}
}catch(InterruptedException e){
System.out.println("Toaster interrupted");
}
System.out.println("Toaster Off");
}
}
class Butterer implements Runnable{
private ToastQueue dryQueue,butteredQueue;
public Butterer(ToastQueue dry,ToastQueue buttered){
dryQueue=dry;
butteredQueue=buttered;
}
public void run(){
try{
while(!Thread.interrupted()){
Toast t=dryQueue.take();
t.butter();
System.out.println(t);
butteredQueue.put(t);
}
}catch(InterruptedException e){
System.out.println("Butterer interrupted");
}
System.out.println("Butterer off");
}
}
class Jammed implements Runnable{
private ToastQueue butteredQueue,finishedQueue;
public Jammed(ToastQueue finished,ToastQueue buttered){
finishedQueue=finished;
butteredQueue=buttered;
}
public void run(){
try{
while(!Thread.interrupted()){
Toast t=butteredQueue.take();
t.jam();
System.out.println(t);
finishedQueue.put(t);
}
}catch(InterruptedException e){
System.out.println("Jammer interrupted");
}
System.out.println("Jammer off");
}
}
class Eater implements Runnable{
private ToastQueue finishedQueue;
private int counter=0;
public Eater(ToastQueue finished){
finishedQueue=finished;
}
public void run(){
try{
while(!Thread.interrupted()){
Toast t=finishedQueue.take();
if(t.getId()!=counter++||
t.getStatus()!=Toast.Status.JAMMED){
System.out.println("--->Error: "+t);
System.exit(1);
}else
System.out.println("Chomp! "+t);
}
}catch(InterruptedException e){
System.out.println("Eater interrupted");
}
System.out.println("Eater off");
}
}
public class ToastOMatic{
public static void main(String[] args)throws Exception{
ToastQueue dryQueue=new ToastQueue(),
butteredQueue=new ToastQueue(),
finishedQueue=new ToastQueue();
ExecutorService exec=Executors.newCachedThreadPool();
exec.execute(new Toaster(dryQueue));
exec.execute(new Butterer(dryQueue,butteredQueue));
exec.execute(new Jammed(butteredQueue,finishedQueue));
exec.execute(new Eater(finishedQueue));
TimeUnit.SECONDS.sleep(5);
exec.shutdownNow();
}
}/*Output
Toast 0: DRY
Toast 0: BUTTERED
Toast 1: DRY
Toast 1: BUTTERED
Toast 2: DRY
Toast 2: BUTTERED
Toast 3: DRY
Toast 3: BUTTERED
Toast 4: DRY
Toast 4: BUTTERED
Toast 5: DRY
Toast 5: BUTTERED
Toast 6: DRY
Toast 6: BUTTERED
Toast 7: DRY
Toast 7: BUTTERED
Toast 8: DRY
Toast 8: BUTTERED
Toast 9: DRY
Toast 9: BUTTERED
Toast 10: DRY
Toast 10: BUTTERED
Toast 11: DRY
Toast 11: BUTTERED
Toast 12: DRY
Toast 12: BUTTERED
Toast 13: DRY
Toast 13: BUTTERED
Toast 14: DRY
Toast 14: BUTTERED
Jammer interrupted
Jammer off
Toaster interrupted
Toaster Off
Eater interrupted
Butterer interrupted
Butterer off
Eater off
*///~
–分散合成关系
批量生产汽车过程中,引擎,动力系统,轮胎分别由各自的生产商制造,再组合装配每一辆汽车,每一辆汽车都是一个完整的线程:
import java.util.*;
import java.util.concurrent.*;
class Car{
private final int id;
private boolean
engine=false,driveTrain=false,wheels=false;
public Car(int idn){id=idn;}
public Car(){id=-1;}
public synchronized int getId(){return id;}
public synchronized void addEngine(){engine=true;}
public synchronized void addDriveTrain(){
driveTrain=true;
}
public synchronized void addWheels(){wheels=true;}
public synchronized String toString(){
return "Car "+id+" [ engine: "+engine+
"driveTrain: "+driveTrain+" wheels: "+wheels+"]";
}
}
class CarQueue extends LinkedBlockingQueue<Car>{}
class ChassisBuilder implements Runnable{
private CarQueue carQueue;
private int counter=0;
public ChassisBuilder(CarQueue cq){carQueue=cq;}
public void run(){
try{
while(!Thread.interrupted()){
TimeUnit.MILLISECONDS.sleep(500);
Car c=new Car(counter++);
System.out.println("ChassisBuilder created"+c);
carQueue.put(c);
}
}catch(InterruptedException e){
System.out.println("Interrupted: ChassisBuilder");
}
System.out.println("ChassisBuilder off");
}
}
class Assembler implements Runnable{
private CarQueue chassisQueue,finishingQueue;
private Car car;
private CyclicBarrier barrier=new CyclicBarrier(4);
private RobotPool robotPool;
public Assembler(CarQueue cq,CarQueue fq,RobotPool rp){
chassisQueue=cq;
finishingQueue=fq;
robotPool=rp;
}
public Car car(){return car;}
public CyclicBarrier barrier(){return barrier;}
public void run(){
try{
while(!Thread.interrupted()){
car=chassisQueue.take();
robotPool.hire(EngineRobot.class,this);
robotPool.hire(DriveTrainRobot.class,this);
robotPool.hire(WheelRobot.class,this);
barrier.await();
finishingQueue.put(car);
}
}catch(InterruptedException e){
System.out.println("Exiting Assembler via interrupt");
}catch(BrokenBarrierException e){
throw new RuntimeException(e);
}
System.out.println("Assembler off");
}
}
class Reporter implements Runnable{
private CarQueue carQueue;
public Reporter(CarQueue cq){carQueue=cq;}
public void run(){
try{
while(!Thread.interrupted()){
System.out.println(carQueue.take());
}
}catch(InterruptedException e){
System.out.println("Exiting Reporter via interrupt");
}
System.out.println("Reporter off");
}
}
abstract class Robot implements Runnable{
private RobotPool pool;
public Robot(RobotPool p){pool=p;}
protected Assembler assembler;
public Robot assignAssembler(Assembler assembler){
this.assembler=assembler;
return this;
}
private boolean engage=false;
public synchronized void engage(){
engage=true;
notifyAll();
}
abstract protected void performService();
public void run(){
try{
powerDown();
while(!Thread.interrupted()){
performService();
assembler.barrier().await();
powerDown();
}
}catch(InterruptedException e){
System.out.println("Exiting "+this+" via interrupt");
}catch(BrokenBarrierException e){
throw new RuntimeException(e);
}
System.out.println(this+" off");
}
private synchronized void powerDown() throws InterruptedException{
engage=false;
assembler =null;
pool.release(this);
while(engage==false)
wait();
}
public String toString(){return getClass().getName();}
}
class EngineRobot extends Robot{
public EngineRobot(RobotPool pool){super(pool);}
protected void performService(){
System.out.println(this+" installing engine");
assembler.car().addEngine();
}
}
class DriveTrainRobot extends Robot{
public DriveTrainRobot(RobotPool pool){super(pool);}
protected void performService(){
System.out.println(this+" installing DriveTrain");
assembler.car().addDriveTrain();
}
}
class WheelRobot extends Robot{
public WheelRobot(RobotPool pool){super(pool);}
protected void performService(){
System.out.println(this+" installing Wheels");
assembler.car().addWheels();
}
}
class RobotPool{
private Set pool=new HashSet();
public synchronized void add(Robot r){
pool.add(r);
notifyAll();
}
public synchronized void
hire(Class extends Robot> robotType,Assembler d)
throws InterruptedException{
for(Robot r: pool)
if(r.getClass().equals(robotType)){
pool.remove(r);
r.assignAssembler(d);
r.engage();
return;
}
wait();
hire(robotType,d);
}
public synchronized void release(Robot r){add(r);}
}
public class CarBuilder{
public static void main(String[] args) throws Exception{
CarQueue chassisQueue=new CarQueue(),
finishingQueue=new CarQueue();
ExecutorService exec=Executors.newCachedThreadPool();
RobotPool robotPool=new RobotPool();
exec.execute(new EngineRobot(robotPool));
exec.execute(new DriveTrainRobot(robotPool));
exec.execute(new WheelRobot(robotPool));
exec.execute(new Assembler(
chassisQueue,finishingQueue,robotPool));
exec.execute(new Reporter(finishingQueue));
exec.execute(new ChassisBuilder(chassisQueue));
TimeUnit.SECONDS.sleep(7);
exec.shutdownNow();
}
}/*Output
ChassisBuilder createdCar 0 [ engine: falsedriveTrain: false wheels: false]
EngineRobot installing engine
WheelRobot installing Wheels
DriveTrainRobot installing DriveTrain
Car 0 [ engine: truedriveTrain: true wheels: true]
ChassisBuilder createdCar 1 [ engine: falsedriveTrain: false wheels: false]
EngineRobot installing engine
WheelRobot installing Wheels
DriveTrainRobot installing DriveTrain
Car 1 [ engine: truedriveTrain: true wheels: true]
ChassisBuilder createdCar 2 [ engine: falsedriveTrain: false wheels: false]
EngineRobot installing engine
WheelRobot installing Wheels
DriveTrainRobot installing DriveTrain
Car 2 [ engine: truedriveTrain: true wheels: true]
ChassisBuilder createdCar 3 [ engine: falsedriveTrain: false wheels: false]
DriveTrainRobot installing DriveTrain
WheelRobot installing Wheels
EngineRobot installing engine
Car 3 [ engine: truedriveTrain: true wheels: true]
ChassisBuilder createdCar 4 [ engine: falsedriveTrain: false wheels: false]
EngineRobot installing engine
DriveTrainRobot installing DriveTrain
WheelRobot installing Wheels
...
Interrupted: ChassisBuilder
ChassisBuilder off
Exiting WheelRobot via interrupt
WheelRobot off
Exiting Assembler via interrupt
Assembler off
Exiting DriveTrainRobot via interrupt
DriveTrainRobot off
Exiting Reporter via interrupt
Reporter off
Exiting EngineRobot via interrupt
EngineRobot off
*///~