生产者/消费者问题、线程池笔记

生产者消费者问题

生产者消费者共享统一资源,两者之间相互依赖、互为条件。

wait() 线程等待,知道其他线程释放锁;

wait(long timeout) 等待指定毫秒数;

notify() 唤醒一个处于等待队列的线程;

notifyAll() 唤醒同一对象上所有调用wait()方法的线程,优先级搞得线程优先调度;

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

管程法

 package com.company;
 //测试:生产者消费者模型----> 管程解决
 
 
 import oracle.jrockit.jfr.ProducerDescriptor;
 
 import java.sql.SQLOutput;
 import java.util.function.Consumer;
 
 public class TestPC {
     public static void main(String[] args) {
         SynContainer container = new SynContainer();
         new Producter(container).start();
         new Comsumers(container).start();
 
    }
 }
 
 //生产者
  class Producter extends Thread {
     SynContainer container;//生产者有一个容器;
     Producter(SynContainer synContainer){//构造时传入容器
         this.container=synContainer;
    }
 
     @Override
     public void run() {//生产
         //循环放入100只鸡
         for (int i = 0; i < 100; i++) {
             container.push(new Chicken(i));
             System.out.println("生产了"+i+"只鸡");
 
        }
    }
 }
 
 
 //消费者
 class  Comsumers extends  Thread {
     SynContainer container;//生产者有一个容器;
     public Comsumers(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 ;
 
     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.notifyAll();
    }
 
     //取走产品
     public synchronized Chicken pop() {
         //判断能否消费
         if (count==0){
             //等待生产者生产
             try {
                 this.wait();
            } catch (InterruptedException e) {
                 e.printStackTrace();
            }
        }
         count --;
         Chicken chicken = chickens[count];
 
         //吃完了,通知生产者生产!!
         this.notifyAll();
 
         return chicken;
    }
 }
 

 

  • 利用缓冲区解决消费者生产者问题


利用信号量法

  • 信号灯法,标志位方法

 /**
  * 测试生产者消费者问题,信号灯机制(falg)
  * 生产者--->演员;消费者-->观众;产品--->节目
  */
 
 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++) {
             this.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:真正的线程池接口。常见子类:ThreadPoolExecutor

    • void execute(Runnable command):执行任务/命令,没有返回值,一般用于Runnable;

    • <T>Future<T> submit(Callable<T> task): 执行任务,有返回值,一般用于Callable;

    • void shutdown():关闭连接池;

  • Executors: 工具类、线程池的工厂类, 用于创建并返回不同类型的线程池

 

  • ExecutorService.execute()线程池服务来实现多线程任务;

 package com.company;
 
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
 public class TestPool {
     public static void main(String[] args) {
         //1、创建服务,创建线程池
         //newFixedThreadPool --->参数为:线程池的大小
         ExecutorService service =Executors.newFixedThreadPool(10);
 
         //执行
         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() {
         System.out.println(Thread.currentThread().getName());
    }
 }

 

  • Callable接口实现:

    1、实现Callable接口,需要返回值类型;

    2、 重写call方法,需要抛出异常;

    3、 创建目标对象;

    4、创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1)

    5、提交执行:Future<Boolean> result1 = ser.submit(t1)

    6、获取结果:boolean r1= result1.get() ;

    7、关闭服务:ser.shutdownNow()

 package com.company;
 
 import org.apache.commons.io.FileUtils;
 
 import java.io.File;
 import java.io.IOException;
 import java.net.URL;
 import java.util.concurrent.*;
 
 /**
  * “多线程实现网络图片下载”
  * callable优势:
  * 1、可以定义返回值;
  * 2、可以抛出异常;
  */
 public class TestCallable implements Callable<Boolean> {
     private String url;//网络图片地址
     private String name;//保存的文件名
 
     public TestCallable(String url,String name ){//重写构造器
         this.url=url;
         this.name=name;
    }
     @Override
     public Boolean call() throws Exception {
         WebDownloader webDownloader =new WebDownloader();
         webDownloader.downloader(url,name);
         System.out.println("下载的文件名为"+name);
         return true;
    }
 
 
     //主方法入口————————
     public static void main(String[] args) throws ExecutionException, InterruptedException {
         TestCallable t1 = new TestCallable("https://wx4.sinaimg.cn/mw2000/006CHHsBly1gzmewybavdj31402eou0y.jpg","多线程下载的网图.jpg");
         TestCallable t2 = new TestCallable("https://wx4.sinaimg.cn/mw2000/006CHHsBly1gzmewybavdj31402eou0y.jpg","多线程下载的网图.jpg");
         TestCallable t3 = new TestCallable("https://wx4.sinaimg.cn/mw2000/006CHHsBly1gzmewybavdj31402eou0y.jpg","多线程下载的网图.jpg");
 
         //创建服务:
         ExecutorService ser = Executors.newFixedThreadPool(1);
         //提交执行
         Future<Boolean> result1=ser.submit(t1);
         Future<Boolean> result2=ser.submit(t2);
         Future<Boolean> result3=ser.submit(t3);
         //获取结果:
         Boolean r1 = result1.get();
         Boolean r2 = result2.get();
         Boolean r13 = result3.get();
         //关闭服务:
         ser.shutdown();
 
    }
 }
 //图片URL:
 //https://wx4.sinaimg.cn/mw2000/006CHHsBly1gzmewybavdj31402eou0y.jpg
 //下载器
 class WebDownloader{
     //下载方法
     public void downloader(String url,String name){
         try {
             FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
             e.printStackTrace();
             System.out.println("IO异常,Downloader方法出现问题");
        }
 
    }
 }
 

 

posted @ 2022-02-25 23:30  devynlime  阅读(81)  评论(0编辑  收藏  举报