28 消费者生产者问题

wait()

解决线程之间的通信问题

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

notify() 唤醒一个处于等待状态的线程

 

管程法

//测试生产者消费模型-->利用缓冲区解决:管程法
public class TestPC {


   public static void main(String[] args) {
       SynContainer container = new SynContainer();
       new Productor(container).start();
       new Consumer(container).start();

  }

}

//生产者
class Productor extends Thread{
   SynContainer container;
   public Productor(SynContainer container) {
       this.container = container;
  }
   //生产

   @Override
   public void run() {
       for (int i = 0; i < 100; i++) {
           System.out.println("生产了"+i+"只鸡");
           container.push(new Chicken(i));
      }
  }
}

//消费者
class Consumer extends Thread{
   SynContainer container;
   public Consumer(SynContainer container) {
       this.container = container;
  }

   @Override
   public void run() {
       for (int i = 0; i < 100; i++) {
           System.out.println("消费了--->"+container.pop().id+"只鸡");
      }
  }
}

//产品
class Chicken{
   int id;
   public  Chicken(int id){
       this.id = id;
  }
}

//缓冲区
class SynContainer{
   //需要一个容器大小
   Chicken[] chickens = new Chicken[10];
   int count = 0;

   //生产者放入产品
       public synchronized void push(Chicken chicken){
           //如果容器满了,就需要等待消费者消费
           if(count == chickens.length){
               //通知消费者消费,生产等待
               try {
                   this.wait();
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
          }

           //如果容器没满,我们就需要丢入产品
          chickens[count] =  chicken;
           count++;

           //可以通知消费者消费了
           this.notify();
      }

   //消费者消费产品
   public synchronized  Chicken pop(){
        //判断能否消费
       if(count == 0){
           //等待生产者生产,消费者等待
           try {
               this.wait();
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
      }

       //如果可以消费
       count--;
       Chicken chicken = chickens[count];
       this.notifyAll();
       //通知生产者生存

       return chicken;
  }
}

 

信号灯法

//测试生产者贤妃这问题2: 信号灯法,标志位解决
public class TestPC2 {
   public static void main(String[] args) {
       TV tv = new TV();
       new Player(tv).start();
       new Watcher(tv).start();
  }

}

//生产者-->演员
class Player extends Thread{
   TV tv;

   public Player(TV tv) {
       this.tv = tv;
  }

   @Override
   public void run() {
       for (int i = 0; i < 20; i++) {
           if(i%2==0){
               this.tv.play("快乐大本营");
          }else{
               this.tv.play("广告");
          }
      }
  }
}


//消费者-->观众
class Watcher extends Thread{
   TV tv;

   public Watcher(TV tv) {
       this.tv = tv;
  }

   @Override
   public void run() {
       for (int i = 0; i < 20; i++) {
           tv.watch();
      }
  }
}

//产品--> 节目
class TV{
   //演员表演,观众等待 true
   //观众观看,演员等待 false
   String voice;//表演的节目
   boolean flag = true;

   //表演
   public synchronized void play(String voice){

       if(!flag){
           try {
               this.wait();
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
      }

       System.out.println("演员表演了:"+ voice);
       //通知观众观看
       this.notifyAll();//唤醒
       this.voice = voice;
       this.flag = !this.flag;  //取反
  }

   public synchronized void watch(){
       if(flag){
           try {
               this.wait();
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
      }
       System.out.println("观看了"+voice);
       //通知演员表演
       this.notifyAll();
       this.flag = !this.flag;  //取反
  }
}

 

使用线程池

背景:创建和销毁,使用量特别大的资源,比如并发情况下的线程,对性能影响很大

思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁,实现重复利用。

好处:

  • 提高响应速度(减少了创建新线程的时间)

  • 降低资源消耗(重复利用线程池中线程,不需要每次都创建)

  • 便于线程管理

    • corePoolSize核心池的大小

    • maximumPoolSize最大线程数

    • keepAliveTime线程没有任务时最多保持多长时间会终止

jdk 5.0 提供了线程池相关的API:ExecutorServiceExecutors

ExecutorService: 真正的线程池接口

Executors 工具类 用于创建并返回不同类型的线程池

public class TestPool {
   public static void main(String[] args) {
       //1.创建服务,创建线程池
       //newFixedThreadPool 参数为:线程池大小
       ExecutorService service = Executors.newFixedThreadPool(10);

       //执行Runnable实现类
       service.execute(new MyThread());
       service.execute(new MyThread());
       service.execute(new MyThread());
       service.execute(new MyThread());

       //2.关闭连接
       service.shutdown();
  }

}


class MyThread implements Runnable{

   @Override
   public void run() {
       for (int i = 0; i < 100; i++) {
           System.out.println(Thread.currentThread().getName());
      }
  }
}

 

posted @   flypiggg  阅读(42)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示