java线程通信

线程通信

生产者 --> 消息队列(缓冲区) --> 消费者

在生产和消费者中,仅有synchronized是不够的

  • synchronized可阻止并发更新同一个共享资源,实现了同步

  • synchronized不能用来实现不同线程之间的消息传递(通信)

java提供了几个方法解决线程之间的通信问题:

  1. wait() 表示线程一直等待,直到其他线程通知,会释放锁,与sleep不同,sleep不释放锁

  2. wait() 指定等待的毫秒数

  3. notify() 唤醒一个处于等待的线程

  4. notifyAll() 唤醒同一个对象上所有调用wait()方法的线程,优先级别高的线程先调度

注意:以上方法均是Object类的方法,且只能在同步方法或同步代码块中使用,否则会抛出异常

方式一(管程法): 利用消息队列(缓冲区)

// 测试:生产者消费者模式->利用队列缓冲区解决:管程法
// 生产者,消费者,产品,消息队列(缓冲区)
public class TestThreadNotify {
   public static void main(String[] args) {
       Queue queue = new Queue();
       new Producer(queue).start();
       new Consumer(queue).start();
  }
}
// 生产者(做鸡)
class Producer extends Thread{
   Queue queue;
   public Producer(Queue queue){
       this.queue = queue;
  }
   @Override
   public void run() {
       for (int i = 0; i < 100; i++) {
           try {
               queue.push(new Chicken(i));
               System.out.println("生产了第 " + i + " 只鸡");
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
      }
  }
}
// 消费者(吃鸡)
class Consumer extends Thread{
   Queue queue;
   public Consumer(Queue queue){
       this.queue = queue;
  }
   @Override
   public void run() {
       for (int i = 0; i < 100; i++) {
           try {
               Chicken c = queue.pop();
               System.out.println("消费了第 " + c.id + " 只鸡");
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
      }
  }
}
// 产品:鸡
class Chicken{
   int id; // 产品编号
   public Chicken(int id) {
       this.id = id;
  }
}
// 消息队列(缓冲区,柜台)
class Queue{
   Chicken[] chickens = new Chicken[10]; // 定义队列大小
   int count = 0; // 队列计数器
   // 生产者 放入产品
   public synchronized void push(Chicken chicken) throws InterruptedException {
       // 如果队列满了,就等待消费者消费
       if (count >= chickens.length) { // 已满则生产者停止生产(等待消费者通知生产者继续生产)
           this.wait();
      }
       // 如果队列没有满,则可以继续向队列中放入产品
       chickens[count] = chicken;
       count++;
       this.notify(); // 通知消费者消费
  }

   // 消费者 取走产品
   public synchronized Chicken pop() throws InterruptedException {
       // 如果队列中没有产品,则等待生产者生产
       Chicken chicken;
       if (count <= 0) {
           this.wait();// 没有产品则停止消费(等待生产者通知消费者继续消费)
      }
       // 如果队列里有产品,则可以消费
       count--;
       chicken = chickens[count];
       this.notify(); // 通知生产者生产
       return chicken;
  }
}

方式二(信号灯法): 利用标志位 信号灯

// 测试:生产者消费者模式:信号灯法
// 生产者,消费者,产品,信号灯
public class TestThreadNotify2 {
   public static void main(String[] args) {
       Counter counter = new Counter();
       new Producer2(counter).start();
       new Consumer2(counter).start();
  }
}
// 生产者(做鸡)
class Producer2 extends Thread{
   Counter counter;
   public Producer2(Counter counter){
       this.counter = counter;
  }
   @Override
   public void run() {
       for (int i = 0; i < 20; i++) {
           counter.push(new Chicken2(i));
           System.out.println("生产了第 " + i + " 只鸡");
      }
  }
}
// 消费者(吃鸡)
class Consumer2 extends Thread{
   Counter counter;
   public Consumer2(Counter counter){
       this.counter = counter;
  }
   @Override
   public void run() {
       for (int i = 0; i < 20; i++) {
           Chicken2 c = counter.pop();
           System.out.println("消费了第 " + c.id + " 只鸡");
      }
  }
}
// 产品(鸡0
class Chicken2{
   int id; // 产品编号
   public Chicken2(int id) {
       this.id = id;
  }
}
// 柜台
class Counter{
   Chicken2 chicken2; // 产品
   boolean flag = true; // *信号灯 (true则允许柜台放入产品,false则不允许)
   // 生产者 放入产品
   public synchronized void push(Chicken2 chicken){
       // 判断柜台是否允许放入产品
       if (!flag) { // 不允许放 则等待
           try {
               this.wait();
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
      }
       // 否则就放入产品
       this.chicken2 = chicken;
       this.flag = !this.flag; // 改变信号灯,停止生产
       this.notifyAll(); // 通信消费者消费
  }
   // 消费者 取走产品
   public synchronized Chicken2 pop(){
       // 判断柜台是否有产品可取
       if (flag) { // true说明柜台暂时没有产品,生产者正在制作,则消费者等待
           try {
               this.wait();
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
      }
       // 否则 取走产品
       this.flag = !this.flag; // 改变信号灯,停止消费
       this.notifyAll(); // 通信生产者生产
       return chicken2;
  }
}
posted @ 2021-12-30 18:23  迷路小孩  阅读(35)  评论(0)    收藏  举报