Java中的线程池和作用,有必要了解一下

337 阅读5分钟
转载自:https://juejin.cn/post/6844903650704392205  

在Java开发中,多线程执行任务是很常见的,Java也提供了线程类Thread来让我们方便创建一个线程如下代码所示

new Thread(){
                @Override
                public void run() {
                    .....

                }
            }.start();

  • 这样创建新的线程有几个缺点
  1. 每次要开启新的线程都需要创建一个,性能差
  2. 线程随意创建,缺乏统一的管理
  3. 不能做到线程的中断
  • 处理上面的这些问题,我们就需要使用线程池来管理线程。
Java SE5d的java.util.concurrent包 提供了Executor(执行器)来管理线程对象。Executor是一个接口,而ExecutorService继承了Excutor接口,ExecutorService是一个具有生命周期的Executor,它知道如何构建恰当的上下文来执行Runnable对象。而ExecutorService对象是使用Executors的静态方法得到Java中的线程池

Executor接口实现

public interface Executor {

    /**
     * Executes the given command at some time in the future.  The command
     * may execute in a new thread, in a pooled thread, or in the calling
     * thread, at the discretion of the {@code Executor} implementation.
     *
     * @param command the runnable task
     * @throws RejectedExecutionException if this task cannot be
     * accepted for execution
     * @throws NullPointerException if command is null
     */
    void execute(Runnable command);
}

  • Java 的四种线程池

-Java中为我们提供了四种线程池,他们分别是FixedThreadPool、CachedThreadPool、ScheduledThreadPool、SingleThreadExector
  1. FixedThreadPool
创建方式为使用Executors的newFixedThreadPool()方法来创建,这种线程池的线程数量是固定的,可以看到他的静态方法需要传入线程的数量,在空闲状态下不会被系统回收,除非它被关闭了。当它的所有线程都在执行任务的时候,新加入的线程就会出来等待状态,等到有线程空闲,新任务才会被执行,如果新任务加入时线程池中有空闲的线程,则意味着它可以快速响应处理任务。

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


 /*
  * 获取使用方法
  */
Runnable r=new Runnable(){
 @Override
 run(){
   .....  
   }
}

ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(r)

CachedThreadPool

创建方式为使用Executors的newCachedThreadPool()方法来创建,由其静态方法可以看出,他的线程数是Integer.MAX_VALUE,可以说他的线程数是无限大,也就是说只要有任务,线程就会立即执行,但是它的每一个线程在空闲状态下是有超时机制的,这个时间为60秒,只要线程空闲时间超过60秒该线程就会被回收,如果所有的线程都处于由空闲状态并且超过了60秒,则相当于线程池中没有任何,线程,也就是说这时的线程池是不占用任何资源的,所以这个线程池比较适合执行大量的耗时较少的任务

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

    /*
    * 获取使用方法
    */
    
    Runnable r=new Runnable(){
    @Override
      run(){
     .....  
     }
    }
    
    ExecutorService executor = Executors.newCachedThreadPool();
    executor.execute(r)

ScheduledThreadPool

创建方式为使用Executors的newCachedThreadPool()方法来创建,这种线程池的核心线程数是固定的,而非核心线程数据是没有限制的,并且当非核心线程空闲的的时候该线程就会被立即回收,所以我们可以使用他来操作定时任务和重复的任务(和Task TimeTask 有些像)

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}

public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
      DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
      new DelayedWorkQueue());
}

/*
 * 获取使用方法
 */
Runnable r=new Runnable(){
  @Override
   run(){
     .....  
    }
 }

 ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
 // 1000ms 后执行任务
 executor.schedule(r,1000,TimeUnit.MICROSECONDS)

 // 延迟1000ms 每隔1000ms 重复执行 任务
 executor.scheduleAtFixedRate(r,1000,1000,TimeUnit.MICROSECONDS)
 

SingleThreadExector

  • 创建方式为使用Executors的newCachedThreadPool()方法来创建,这种线程只有唯一一个核心线程,并且保证所有执行的的任务都在这一个线程中执行,并且是顺序执行,也就不用在考虑线程同步的问题了。

public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
    (new ThreadPoolExecutor(1, 1,
                            0L, TimeUnit.MILLISECONDS,
                            new LinkedBlockingQueue<Runnable>()));
 }
 
  /*
   * 获取使用方法
   */
 ExecutorService executor = Executors.newSingleThreadExecutor();
 executor.execute(r)
 
 
 Runnable r=new Runnable(){
  @Override
   run(){
  .....  
  }
 }

 ExecutorService executor = Executors.newSingleThreadExecutor();
 executor.execute(r)

通过上面对Java四种线程池的介绍,我们可以发现最终都是新建ThreadPoolExecutor对象,也就是说ThreadPoolExecutor才是线程池的核心实现。

ThreadPoolExecutor 比较常用的一个构造方法

 public ThreadPoolExecutor(int corePoolSize,
                        int maximumPoolSize,
                        long keepAliveTime,
                        TimeUnit unit,
                        BlockingQueue<Runnable> workQueue,
                        ThreadFactory threadFactory) {
  this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
       threadFactory, defaultHandler);
 }

//参数含义
corePoolSize:默认情况下核心线程数会一直存在,不管是否处于闲置状态,
但是如果线程池设置了核心线程数,也就是ThreadPoolExecutor的allowCoreThreadTimeOut这个boolean
为true,如果核心线程数为零,则allowCoreThreadTimeOut的值为true,超时时间为keepAliveTime的值,
也就是CachedThreadPool线程池的所有线程都能够回收的原因,他的核心线程数为零,也就是没有核心线程

maximumPoolSize:最大线程数

keepAliveTime:非核心线程超时时长,如果allowCoreThreadTimeOut的值为true,
则该超时时长也会作用于空闲状态的核心线程

unit:超时时长的时间单位 TimeUnit.MILLISECONDS/SECONDS/MINUTES(毫秒/秒/分钟)

workQueue:线程任务队列,存放线程任务

threadFactory:线程池线程生产工厂,为线程池创建新线程

//我们看到构造放中还有一个defaultHandler参数,他其实是RejectedExecutionHandler对象
defaultHandler:当线程队列满了,或者线程任务无法执行则用该参数抛出通知RejectedExecutionException,这里构造方法暂时没用到

在Android中我们可以写自己的线程管理类接,下面就来实现一个自己的线程池管理类来管理我们的线程

/**
 * Created by 毛麒添 on 2018/8/1 0010.
 * 线程管理类,线程池为单例
 */

public class ThreadManager {

private static ThreadPool mThreadPool;

public static ThreadPool getmThreadPool(){
  if (mThreadPool==null){
      synchronized (ThreadManager.class){
          if(mThreadPool==null){
              //线程安全
              mThreadPool=new ThreadPool(5,10,1L);
          }
      }
    }
   return mThreadPool;
}


//线程池
public static class ThreadPool{

  private int corePoolSize;//核心线程数 5
  private int maximumPoolSize;//最大线程数 10
  private long keepAliveTime;//线程休眠时间 1秒

  private ThreadPoolExecutor executor;

  private ThreadPool(  int corePoolSize, int maximumPoolSize,long keepAliveTime){
        this.corePoolSize=corePoolSize;
        this.maximumPoolSize=maximumPoolSize;
        this.keepAliveTime=keepAliveTime;
  }


  public void execute(Runnable runnable){
      /**
       * int corePoolSize, 核心线程数
       * int maximumPoolSize, 最大线程数
       * long keepAliveTime, 线程休眠时间
       * TimeUnit unit, 时间单位
       * BlockingQueue<Runnable> workQueue, 线程队列
       * ThreadFactory threadFactory, 生成线程的工厂
       */
      if(executor==null){
          executor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,
                  TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(),
                  Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
      }
      //核心线程也有超时机制
      executor.allowCoreThreadTimeOut(true);
      executor.execute(runnable);
  }
  //取消任务,从任务队列中将其移除
  public void cancelTask(Runnable runnable){
      if(runnable!=null){
          executor.getQueue().remove(runnable);
       }

     }
  }

}


//使用
ThreadManager.getmThreadPool().execute(new Runnable() {
          @Override
          public void run() {
              //执行任务
          }
      });