zoukankan      html  css  js  c++  java
  • 第二部分:并发工具类22->Executor与线程池,如何创建正确的线程池

    1.创建线程

    创建对象,仅仅在jvm堆里分配一块内存
    创建线程,调用操作系统内核api,操作系统为线程分配一系列资源,线程是重量级对象,应该避免频繁创建和销毁

    2.线程池

    线程池和一版池化资源不同,一般池化资源是acquire申请资源,release释放资源
    java提供的线程池里没有申请线程和释放线程的方法

    
    class XXXPool{
      // 获取池化资源
      XXX acquire() {
      }
      // 释放池化资源
      void release(XXX x){
      }
    }  
    

    3.线程池是一种生产者-消费者模式

    而不是普通池化资源的使用方式
    线程池使用方式生产者
    线程池本身是消费者

    线程池设计思想
    内嵌队列,以及工作线程

    
    //简化的线程池,仅用来说明工作原理
    class MyThreadPool{
      //利用阻塞队列实现生产者-消费者模式
      BlockingQueue<Runnable> workQueue;
      //保存内部工作线程
      List<WorkerThread> threads 
        = new ArrayList<>();
      // 构造方法
      MyThreadPool(int poolSize, 
        BlockingQueue<Runnable> workQueue){
        this.workQueue = workQueue;
        // 创建工作线程
        for(int idx=0; idx<poolSize; idx++){
          WorkerThread work = new WorkerThread();
          work.start();
          threads.add(work);
        }
      }
      // 提交任务
      void execute(Runnable command){
        workQueue.put(command);
      }
      // 工作线程负责消费任务,并执行任务
      class WorkerThread extends Thread{
        public void run() {
          //循环取任务并执行
          while(true){ ①
            Runnable task = workQueue.take();
            task.run();
          } 
        }
      }  
    }
    
    /** 下面是使用示例 **/
    // 创建有界阻塞队列
    BlockingQueue<Runnable> workQueue = 
      new LinkedBlockingQueue<>(2);
    // 创建线程池  
    MyThreadPool pool = new MyThreadPool(
      10, workQueue);
    // 提交任务  
    pool.execute(()->{
        System.out.println("hello");
    });
    

    线程池中有多少个线程,就起多少个工作线程WorkerThread
    execute只是把任务提交到queue中,线程池内部维护的工作线程会消费queue中的任务并执行

    4.如何用java中的线程池

    
    ThreadPoolExecutor(
      int corePoolSize,
      int maximumPoolSize,
      long keepAliveTime,
      TimeUnit unit,
      BlockingQueue<Runnable> workQueue,
      ThreadFactory threadFactory,
      RejectedExecutionHandler handler) 
    

    corePoolSize : 最小线程数,有些项目很闲,至少保留corePoolSize坚守阵地
    maximumPoolSize:线程池最大线程数
    keepAliveTime & unit : 一个线程在一段时间内,没有执行任务,说明很闲。keepaliveTime 和unit定义这个一段时间参数,如果一个线程空闲了keepaliveTime & unit 这么久 ,并且线程池的线程数量大于corePoolSize,那么空闲线程就要回收

    workQueue:工作队列
    threadFactory:定义如何创建线程,给线程指定有意义的名字
    handler:定义任务的拒绝策略,如果线程池所有线程都在忙,工作队列也满了,那么提交任务,线程池就会拒绝接收
    以下4种拒绝策略:
    CallerRunsPolicy:提交任务的线程自己去执行该任务。
    AbortPolicy:默认拒绝策略,会throws RejectedExecutionException。
    DiscardPolicy:直接丢弃任务,没有任何异常抛出。
    DiscardOldestPolicy:丢弃最老的任务,把最早进入工作队列的任务丢弃,然后把新任务加入到工作队列。

    5.使用线程池的注意事项

    目前大厂都不建议直接使用静态工厂类Executors了
    主要原因是Executors提供的很多方法默认使用的是无界队列LinkedBlockingQueue,高负载情况,无界队列很容易OOM
    OOM会导致所有请求无法处理,致命问题,所以建议使用有界队列

    使用有界队列,任务过多时,默认拒绝策略会throw RejectedExecutionException运行时异常,运行时异常编译器不强制catch它,开发人员很容易忽略,拒绝策略要谨慎使用。线程池处理的任务非常重要,建议自定义拒绝策略,自定义拒绝策略往往和降级策略配合使用

    线程池里面提交任务,任务要自己捕获异常。

    原创:做时间的朋友
  • 相关阅读:
    枚举
    IOS uitableview代理方法
    IOS图片拉伸模式
    IOS单例的设计模式
    圆角属性
    IOS 随机数
    IOS正则表达式
    添加 分类 自动适配图片
    用grep查找文件内容
    Openscada远程配置
  • 原文地址:https://www.cnblogs.com/PythonOrg/p/14982132.html
Copyright © 2011-2022 走看看