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

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

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

                }
            }.start();

  • 这样创建新的线程有几个缺点

    • 每次要开启新的线程都需要创建一个,性能差
    • 线程随意创建,缺乏统一的管理
    • 不能做到线程的中断
  • 处理上面的这些问题,我们就需要使用线程池来管理线程。

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

    • 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() {
                    //执行任务
                }
            });
      
      

好了,这就是我所了解的线程池知识,如果有错,请给我留言指出,大家一起学习进步。

  • 参考资料:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,265评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,274评论 1 288
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,087评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,479评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,782评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,218评论 1 207
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,594评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,316评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,955评论 1 237
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,274评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,803评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,177评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,732评论 3 229
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,953评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,687评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,263评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,189评论 2 258

推荐阅读更多精彩内容

  • 一.Java中的ThreadPoolExecutor类 java.uitl.concurrent.ThreadPo...
    谁在烽烟彼岸阅读 624评论 0 0
  • Label是比较常用的一个控件,记录一些比较使用的技术 一、计算Label的高度 计算单行指定字体大小下的高度 具...
    Onegeng阅读 1,451评论 0 2
  • 女儿:这几天连续下雨,女儿早上又在说咋去,我提出让她自己走路去学校,她不同意:要求我陪她走路。。。1.是一个想要与...
    7556497b805f阅读 155评论 0 0