[size=medium] 上篇日志所提到的Xiaonei Brush程序是存在Bug的,这个Bug即信息输出是不可预测的。什么问题呢?原来的程序通过一个线程来打印信息,该线程类为:PrintInfo(String msg,JTextArea area),msg是要输出的信息,而area是输出的dest.类声明为public PrintInfo extends Thread,当需要打印信息的时候,即通过:
new PrintInfo("我要打印一条信息",area);
实现,此种方式的弊端即在于线程调度时每个PrintInfo的运行时机是不可测的("你永远都不知道一个线程何时在运行"),即产生前面所说的Bug,信息输出时产生了错位。如:我有三条信息要输出
#1: new PrintInfo("This is 1st message",area);
#2: new PrintInfo("This is 2nd message",area);
#3: new PrintInfo("This is 3rd message",area);
当程序运行时,线程的运行顺序并不一定是按照#1,#2,#3来运行的,可能是#3,#2,#1,因此产生了错位.一个进一步的说明:第一个被调度的线程是#1,#1线程终止后并没有使#2进入运行状态而是将之挂起而运行#3.
由此引出生产者消费者问题生产者与消费者问题可以被描述为:一个有限缓冲区和两类线程,它们是生产者和消费者,生产者把产品放入缓冲区,相反消费者便是从缓冲区中拿走产品。 生产者在缓冲区满时必须等待,直到缓冲区有空间才继续生产。消费者在缓冲区空时必须等待,直到缓冲区中有产品才能继续读取。
PrintInfo是消费者,它从缓冲区中取出消息将之打印.而主类以及Brush线程是生产者,它们产生消息并放入缓冲区.在参考相关资料后,我使用BlockingQueue来实现生产者消费者,方法很简单,具体地是使用了SynchronousQueue,SynchronousQueue实现了BlockingQueue接口,SynchronousQueue是一种阻塞队列,其中每个插入操作必须等待另一个线程的对应移除操作.
BlockingQueue queue=new SynchronousQueue<String>();
queue.put("放入消息");
String msg=queue.take();//take()获取并移除队列的头
******************************************************************
class Producer implements Runnable{
private final BlockingQueue<String> queue;
public Producer(BlockingQueue queue){
this.queue=queue;
}
public void run(){
...........要执行的代码
print(msg):
............
}
private void print(String msg){
try {
queue.put(msg);
} catch (InterruptedException e) {}
}
}
//消费者代码省略,和生产者区别不大,run方法:
while(true){
try{
while(true){
print(queue.take());
}
}catch (InterruptedException ex) {}
}
//测试类
BlockingQueue<String> queue=new SynchronousQueue<String>();
Producer p=new Producer(queue);
Consumer c=new Consumer(queue);
Thread tp=new Thread(p);
Thread tc=new Thread(c);
tp.run();
tc.run();
改写代码后,运行正常,信息输出不再错位.其他的解决方式留待以后再去看~
[/size]
new PrintInfo("我要打印一条信息",area);
实现,此种方式的弊端即在于线程调度时每个PrintInfo的运行时机是不可测的("你永远都不知道一个线程何时在运行"),即产生前面所说的Bug,信息输出时产生了错位。如:我有三条信息要输出
#1: new PrintInfo("This is 1st message",area);
#2: new PrintInfo("This is 2nd message",area);
#3: new PrintInfo("This is 3rd message",area);
当程序运行时,线程的运行顺序并不一定是按照#1,#2,#3来运行的,可能是#3,#2,#1,因此产生了错位.一个进一步的说明:第一个被调度的线程是#1,#1线程终止后并没有使#2进入运行状态而是将之挂起而运行#3.
由此引出生产者消费者问题生产者与消费者问题可以被描述为:一个有限缓冲区和两类线程,它们是生产者和消费者,生产者把产品放入缓冲区,相反消费者便是从缓冲区中拿走产品。 生产者在缓冲区满时必须等待,直到缓冲区有空间才继续生产。消费者在缓冲区空时必须等待,直到缓冲区中有产品才能继续读取。
PrintInfo是消费者,它从缓冲区中取出消息将之打印.而主类以及Brush线程是生产者,它们产生消息并放入缓冲区.在参考相关资料后,我使用BlockingQueue来实现生产者消费者,方法很简单,具体地是使用了SynchronousQueue,SynchronousQueue实现了BlockingQueue接口,SynchronousQueue是一种阻塞队列,其中每个插入操作必须等待另一个线程的对应移除操作.
BlockingQueue queue=new SynchronousQueue<String>();
queue.put("放入消息");
String msg=queue.take();//take()获取并移除队列的头
******************************************************************
class Producer implements Runnable{
private final BlockingQueue<String> queue;
public Producer(BlockingQueue queue){
this.queue=queue;
}
public void run(){
...........要执行的代码
print(msg):
............
}
private void print(String msg){
try {
queue.put(msg);
} catch (InterruptedException e) {}
}
}
//消费者代码省略,和生产者区别不大,run方法:
while(true){
try{
while(true){
print(queue.take());
}
}catch (InterruptedException ex) {}
}
//测试类
BlockingQueue<String> queue=new SynchronousQueue<String>();
Producer p=new Producer(queue);
Consumer c=new Consumer(queue);
Thread tp=new Thread(p);
Thread tc=new Thread(c);
tp.run();
tc.run();
改写代码后,运行正常,信息输出不再错位.其他的解决方式留待以后再去看~
[/size]