Thread & ExecutorService & ThreadPoolExecutor 总览

简介: Thread & ExecutorService & ThreadPoolExecutor 总览ExecutorService类方法shutdown 允许已经提交的任务(尚未开始执行和已经开始执行...

Thread & ExecutorService & ThreadPoolExecutor 总览

ExecutorService

类方法

这里写图片描述

  1. shutdown
    允许已经提交的任务(尚未开始执行和已经开始执行的)继续执行
  2. shutdownNow
    尚未开始执行的任务不再执行,同时尝试终止正在执行的任务
  3. 无论是shutdown 还是shutdownNow,两个的执行都会阻止新的任务提交

  4. 一个ExecutorService一旦termination,表明没有正在执行的任务,没有等待执行的任务,也不会有新的任务可以被提交。

  5. 如果一个ExecutorService不再使用,应该调用shutdown方法来回收资源。

  6. submit方法(三个重载方法)

    返回的Future对象可以用来取消任务和等待任务执行完成
  7. invokeAny和invokeAll方法

    用户批量执行任务,
    invokeAny:会阻塞当前线程,直到某个任务完成。并返回这个任务相关的Future对象
    invokeAll:会阻塞当前线程,直到所有任务完成。
  8. 两阶段shutdown

    1. 先执行shutdown方法
    2. 调用awaitTermination方法
    3. 再调用shutdownNow方法
    void shutdownAndAwaitTermination(ExecutorService pool) {
       pool.shutdown(); // Disable new tasks from being submitted
       try {
         // Wait a while for existing tasks to terminate
         if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
           pool.shutdownNow(); // Cancel currently executing tasks
           // Wait a while for tasks to respond to being cancelled
           if (!pool.awaitTermination(60, TimeUnit.SECONDS))
               System.err.println("Pool did not terminate");
         }
       } catch (InterruptedException ie) {
         // (Re-)Cancel if current thread also interrupted
         pool.shutdownNow();
         // Preserve interrupt status
         Thread.currentThread().interrupt();
       }
    }
  9. isShutdown和isTerminated分别对应于两个状态:关闭状态,终结状态

Thread

  1. interrupt方法
    如果执行a.interrupt方法后,如果a线程(注意是a线程,不是调用线程)抛出了InterruptedException异常,那么a的中断状态会被清除。如果不是抛出InterruptedException异常,那么a的中断状态都会被设置。
  2. interrupted方法
    执行a.interrupted方法会返回a线程的中断状态,同时会清除a线程的中断状态
  3. isInterrupted方法
    执行a.interrupted方法会返回a线程的中断状态,不会清除a线程的中断状态

ThreadPoolExecutor

  1. core pool size 及 max pool size

    一个新的任务提交哪些情况下回创建新的线程:
        1. 已创建的的线程数小于corePoolSize(即便有线程是空闲的)
        2. 已创建的线程数大于corePoolSize小于maxPoolSize,同时任务队列已经满的情况下,也会创建新的线程
    
    可以动态改变这两个的值:setCorePoolSize  以及 setMaximumPoolSize
    
    如果corePoolSize==maxinumPoolSize,那么则创建了一个固定大小的线程池
  2. keep alive time

    如果已创建的线程大于了corePoolSize,并且如果有线程的空闲时间大于了keepAliveTime,那么这些线程会被kill掉直到剩下corePoolSize个线程。
    
    可以动态设置:setKeepAliveTime方法
    
    默认情况下keep-alive策略只会针对已创建线程数大于corePoolSize的情况下
    
    可以通过执行allowCoreThreadTimeOut(boolean)让keep-alive策略应用在已创建线程数小于corePoolSize的情况下。
  3. BlockingQueue

    1. 如果已创建线程数小于corePoolSize,那么会创建新的线程来执行当前提交的任务,而不是进入阻塞队列
    2. 如果已创建线程数大于等于corePoolSize,会尝试先进入阻塞队列,如果进入失败(其实就是队列已满),则会在maxPoolSize条件下创建新的线程来执行当前提交的任务。如果不满足maxPoolSize条件,那么就会执行 拒绝执行策略(默认的拒绝执行策略见下)
    3. 通常有三种入队列策略

      1. 直接传递给线程(Direct handoffs)

        比如:SychronousQueue
        
        感觉可以理解为这个入队列会总是失败,就相当于没有这个队列一样。这样就能在maxPoolSize条件下尽可能快的创建(或选择空闲的线程)来执行新提交的任务。
        
        如果提交的任务有互相的依赖性,可以考虑使用这种队列。
        
        public static ExecutorService newCachedThreadPool() {
            return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                          60L, TimeUnit.SECONDS,
                                          new SynchronousQueue<Runnable>());
        }
      2. 无界队列(Unbounded Queue)

        比如:LinkedBlockingQueue
        
        可以理解为如果有任务需要入队列,那么总会入队成功。
        因此按照创建新线程的条件,理论上不会有超过corePoolSize个数的线程。也就是说理论上线程数最多为corePoolSize,因此maxPoolSize的设置也就显得没有意义了。
        
        如果提交的任务互相间没有依赖性,可以考虑使用这种队列
      3. 有界队列(Bounded Queue)

        比如:ArrayBlockingQueue
        
        如果使用有限个maxPoolSize,那么使用这种队列可以防止资源的耗尽。
        
        使用长队列和小的线程池,可以降低CPU使用率,降低系统资源的消耗,以及降低线程上下文切换的消耗,但是会导致低吞吐量。如果任务频繁的阻塞,系统可能会创建比允许的线程数多的线程。
        
        使用短队列和大的线程池,可以提高CPU使用率,但也有可能导致吞吐量下降。
  4. 拒绝执行策略(我自己的叫法,实际上就是 RejectedExceptionHandler )

    这里写图片描述

    1. ThreadPoolExecutor.AbortPolicy
      抛出RejectedExecutionException异常

      public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
          throw new RejectedExecutionException("Task " + r.toString() +
                                               " rejected from " +
                                               e.toString());
      }
    2. ThreadPoolExecutor.CallerRunsPolicy
      在调用线程上执行(哪个线程提交的任务就哪个线程执行)

      public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
          if (!e.isShutdown()) {
              r.run();
          }
      }
  5. ThreadPoolExecutor.DiscardPolicy
    直接放弃

    ```
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    }
    ```
    
    1. ThreadPoolExecutor.DiscardOldestPolicy
      放弃当前队列中第一个任务

      public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
          if (!e.isShutdown()) {
              e.getQueue().poll();
              e.execute(r);
          }
      }
  6. Finalization

    一个在程序中不再被引用的线程池如果同时没有剩余的线程,那么这个线程池会被自动的shutdown.
    
    因此如果你想即便在忘记执行shutdown方法的时候仍能正常关闭线程池,那么建议设置一个有限的keepAliveTime(针对大于线程数大于corePoolSize的那些线程),同时也执行下 allowCoreThreadTimeOut(boolean) . 

欢迎关注公众号
70

目录
相关文章
|
2月前
|
Java
在 Java 中 Runnable 与 Thread 的适时运用
【8月更文挑战第22天】
21 0
|
Java
The Pitfalls of Using Executors to Create Thread Pools in Java
While the Executors class provides a convenient way to create thread pools in Java, it comes with inherent limitations that may not suit every use case. Blindly using Executors can lead to uncontrolled thread growth, task loss, and difficulties in handling exceptions. For robust and efficient concur
65 0
|
存储 监控 Java
【小家java】Java定时任务ScheduledThreadPoolExecutor详解以及与Timer、TimerTask的区别(执行指定次数停止任务)(上)
【小家java】Java定时任务ScheduledThreadPoolExecutor详解以及与Timer、TimerTask的区别(执行指定次数停止任务)(上)
ThreadPoolExecutor的中的submit和FutureTask || 通过Executors 创建线程池的一些实例(Callable和Runnable的在其中的体现)
ThreadPoolExecutor的中的submit和FutureTask || 通过Executors 创建线程池的一些实例(Callable和Runnable的在其中的体现)
183 0
|
安全 Java
通过java提供的Timer实现定时任务
有时需要项目自己定时做一些任务,如数据统计、邮件发送、节日祝福等操作,这时可以使用Java提供的Timer来实现定时任务的执行。
169 0
通过java提供的Timer实现定时任务
|
数据采集 缓存 安全
Executors 与 Thread 比较
Executors 与 Thread 比较
94 0
|
Java 调度 API
java之Thread.sleep(long)与object.wait()/object.wait(long)的区别及相关概念梳理(good)
一、Thread.sleep(long)与object.wait()/object.wait(long)的区别sleep(long)与wait()/wait(long)行为上有些类似,主要区别如下:1.Thread.sleep(long)是属于Thread类的静态方法。
1363 0
|
Java API 调度
【小家java】Java定时任务ScheduledThreadPoolExecutor详解以及与Timer、TimerTask的区别(执行指定次数停止任务)(下)
【小家java】Java定时任务ScheduledThreadPoolExecutor详解以及与Timer、TimerTask的区别(执行指定次数停止任务)(下)
Java三种线程创建调用方式-Thread、Runnable与Callable
继承类Thread与实现接口Runnable类似,因为Thread也是实现了接口Runnable; 继承类Thread与实现接口Runnable的run方法与start方法都会调用执行体,run同步执行,start异步执行; 实现接口Callable的线程被调用时,主线程会阻塞等待执行结果; 值得注意的是:实现接口Callable的线程名称和主线程名称一样。
166 0