chapter08_线程池的使用_3_配置ThreadPoolExecutor

  • Executors的简单工厂可以创建多种类型的线程池

    (1) newFixedThreadPool

    线程池长度固定,每当提交一个任务时就创建一个线程,直到达到线程池的最大数量;如果某个线程抛出未捕捉的Exception,则线程池捕捉一个新的线程

      public static ExecutorService newFixedThreadPool(int nThreads) {
          return new ThreadPoolExecutor(nThreads, nThreads,
                                        0L, TimeUnit.MILLISECONDS,
                                        new LinkedBlockingQueue<Runnable>());
      }
    
      或
    
      public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
          return new ThreadPoolExecutor(nThreads, nThreads,
                                        0L, TimeUnit.MILLISECONDS,
                                        new LinkedBlockingQueue<Runnable>(),
                                    threadFactory);
    

    (2) newCachedThreadPool

    线程池的规模不存在限制:如果线程池的当前规模超过了处理需求,则回收空闲的线程;如果需求增加,则添加新的线程

      public static ExecutorService newCachedThreadPool() {
          return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                        60L, TimeUnit.SECONDS,
                                        new SynchronousQueue<Runnable>());
      }
    
      或
    
      public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
          return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                        60L, TimeUnit.SECONDS,
                                        new SynchronousQueue<Runnable>(),
                                        threadFactory);
      }
    

    (3) newSingleThreadExecutor

    创建单个线程来执行任务,并保证任务执行的任何内存写入操作对于后续任务可见,确保按照任务在队列中的顺序来执行

      public static ExecutorService newSingleThreadExecutor() {
          return new FinalizableDelegatedExecutorService
              (new ThreadPoolExecutor(1, 1,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>()));
      }
    
      或
    
      public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
          return new FinalizableDelegatedExecutorService
              (new ThreadPoolExecutor(1, 1,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory));
      }
    

    (4) newScheduledThreadPool

    创建固定长度的线程池,以延迟或定时的方式执行任务

      public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
          return new ScheduledThreadPoolExecutor(corePoolSize);
      }
    
      或
    
      public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory) {
          return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
      }
    

    它们有一个共同的特点:就是底层都是用的ThreadPoolExecutor类

    ThreadPoolExecutor构造函数的最通用形式

      public ThreadPoolExecutor(
                            int corePoolSize,
                            int maximumPoolSize,
                            long keepAliveTime,
                            TimeUnit unit,
                            BlockingQueue<Runnable> workQueue,
                            ThreadFactory threadFactory,
                            RejectedExecutionHandler handler) {
          ...
      }
    
      参数说明
    

    @param corePoolSize the number of threads to keep in the pool, even if they are idle, unless {@code allowCoreThreadTimeOut} is set

    @param maximumPoolSize the maximum number of threads to allow in the pool

    @param keepAliveTime when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.

    @param unit the time unit for the {@code keepAliveTime} argument

    @param workQueue the queue to use for holding tasks before they are executed. This queue will hold only the {@code Runnable} tasks submitted by the {@code execute} method.

    @param threadFactory the factory to use when the executor creates a new thread

    @param handler the handler to use when execution is blocked because the thread bounds and queue capacities are reached

  • 线程的创建和销毁

    (1) 基本大小corePoolSize

    线程池的目标大小,即在没有任务执行时线程池的大小,并且只有在工作队列满了的情况下才会创建超出这个数量的线程

    (2) 最大大小maximumPoolSize

    可同时活动的线程数量的上限

    (3) 存活时间keepAliveTime

    如果某个线程的空闲时间超过了存活时间,那么将标记为__可回收__;当线程池的__当前大小超过了基本大小__时,这个线程将被终止

  • 管理队列任务

    (1) workQueue参数用来管理一个Runnable队列

    (2) 队列的排队方法有3种

    1° 无界队列

    2° 有界队列

    3° 同步移交队列 SynchronousQueue

    要求:要将一个元素放入SynchronousQueue中,必须有另一个线程正在等待这个元素

    注:

    使用SynchronousQueue更高效,因为任务会直接移交给执行它的线程,而不是首先放在队列中

  • 饱和策略

    (1) 应用场景

    当__有界队列__被任务__填满__后,接下来到来的任务该如何处理

    (2) 饱和策略

    1° 中止Abort

    直接抛出未检查异常RejectedExecutionException

    a. 抛弃Discard

    抛弃后来的任务

    b. 抛弃最旧的Discard-Oldest

    抛弃队列中最前面的任务

    2° 调用者运行

    把无法放在队列中的任务,返回给调用者,然后在调用者的线程中执行这个任务

    这种策略的__主要思想__是:调用者执行这个任务,那么这段时间它就无法提交任务;趁这个时间线程池中的任务有的也可以跑完了

    使用示例:

    如果服务器过载,主线程就不再accept(),于是到达的请求会在TCP层的队列中等待,然后TCP接收窗口会变小,然后就会让发送方慢点发送

    线程池 --> 服务器应用程序 --> 服务器TCP层 --> 客户端TCP层

    (3) 饱和策略的设置方式

      executor.setRejectExecutionHandler();
    

    或者在构造函数中的handler参数设置

  • 线程工厂threadFactory参数

    (1) 每当线程池需要创建一个线程时,都是通过threadFactory指定的线程工厂来创建新线程

      public interface ThreadFactory {
    
          Thread newThread(Runnable r);
      }
    

    (2) 默认的线程工厂是Executors.defaultThreadFactory(),它会创建一个新的、非守护的线程,不包含任何特殊的配置信息

    (3) 为了定制化创建线程,可以自己实现ThreadFactory

    示例

    MyThreadFactory.java

      public class MyThreadFactory implements ThreadFactory {
    
          private final String poolName;
    
          public MyThreadFactory(String poolName) {
              this.poolName = poolName;
          }
    
          @Override
          public Thread newThread(Runnable runnable) {
              return new MyAppThread(runnable, poolName);
          }
      }
    

    MyAppThread.java

      public class MyAppThread extends Thread {
    
          private static volatile boolean debugLifecycle = false;
          private static final AtomicInteger created = new AtomicInteger();
          private static final AtomicInteger alive = new AtomicInteger();
          private static final Logger log = Logger.getAnonymousLogger();
    
          public MyAppThread(Runnable r) {
              this(r, DEFAULT_NAME);
          }
    
          public MyAppThread(Runnable runnable, String name) {
    
              super(runnable, name + "-" + created.incrementAndGet());
    
              super.setUncaughtExceptionHandler(
                  new Thread.UncaughtExceptionHandler() {
    
                      @Override
                      public void uncaughtException(
                              Thread t, Throwable e) {
                          log.log(Level.SEVERE, "UNCAUGHT in thread " + t.getName(), e);
                      }
                  });
          }
    
          public void run() {
    
              // Copy debug flag to ensure consistent value throughout.
              boolean debug = debugLifecycle;
    
              if (debug) {
                  log.log(Level.FINE, "Created " + getName());
              }
    
              try {
                  alive.incrementAndGet();
                  super.run();
              } finally {
                  alive.decrementAndGet();
                  if (debug) {
                      log.log(Level.FINE, "Exiting " + getName());
                  }
              }
          }
    
          public static int getThreadsCreated() {
              return created.get();
          }
    
          public static int getThreadsAlive() {
              return alive.get();
          }
    
          public static boolean getDebug() {
              return debugLifecycle;
          }
    
          public static void setDebug(boolean b) {
              debugLifecycle = b;
          }
      }
    

    将MyThreadFactory作为参数,每次线程池需要创建线程时,会new一个MyAppThread类型的Thread,MyAppThread定制化添加了Log、统计MyAppThread线程数量等功能

  • 调用构造函数后再定制ThreadPoolExecutor的方法

    (1) 如果已经调用过ThreadPoolExecutor的构造函数,那么可以用ThreadPoolExecutor的setXXX方法进行设置

    (2) 如果是通过Executors的工厂方法创建的ThreadPoolExecutor,它的类型是ExecutorService,这时可以判断一下再set

      ExecutorService exec = Executors.newCachedThreadPool();
      
      if ( exec instanceof ThreadPoolExecutor) {
          ((ThreadPoolExecutor)exec).setCorePoolSize(10);
      } else {
          throw new AssertionError("Bad assumption");
      } 
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值