生产者与消费者----Java线程同步

      上篇日志所提到的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();

改写代码后,运行正常,信息输出不再错位.其他的解决方式留待以后再去看~

你可能感兴趣的:(java,thread,C++,c,C#)