美文网首页
Android基础 java线程池详解

Android基础 java线程池详解

作者: LiuJP | 来源:发表于2019-12-25 11:29 被阅读0次

    Executor框架是一种将线程的创建和执行分离的机制。它基于Executor和ExecutorService接口,及这两个接口的实现类ThreadPoolExecutor展开,Executor有一个内部线程池,并提供了将任务传递到池中线程以获得执行的方法,可传递的任务有如下两种:通过Runnable接口实现的任务和通过Callable接口实现的任务。在这两种情况下,只需要传递任务到执行器,执行器即可使用线程池中的线程或新创建的线程来执行任务。执行器也决定了任务执行时间。

    java提供了四种线程池的实现:
    (1)newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
    (2)newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
    (3)newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
    (4)newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
    下面就对这些线程池的使用方式进行简要的代码介绍:

    首先是可缓存线程池:

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
     
    public class ThreadPoolDemo {
        public static void main (String[] args) {
            ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
            for(int i = 0; i < 10; i++) {
                final int index = i;
                try {
                    Thread.sleep(index*1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                cachedThreadPool.execute(new Runnable () {
                    public void run () {
                        System.out.println(index);
                    }
                });
            }
        }
    }
    

    然后是定长线程池:

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
     
    public class ThreadPoolDemo {
        public static void main (String[] args) {
            ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
            for(int i = 0; i < 10; i++) {
                final int index = i;
                fixedThreadPool.execute(new Runnable () {
                    public void run () {
                        System.out.println(index);
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                });
            }
        }
    }
    

    然后是定长线程池支持定时和周期性任务:

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
     
    public class ThreadPoolDemo {
        public static void main (String[] args) {
            ScheduledExecutorService scheduleThreadPool = Executors.newScheduledThreadPool(5);
            scheduleThreadPool.schedule(new Runnable() {
                public void run() {
                    System.out.println("delay 3 seconds");
                }
            }, 3, TimeUnit.SECONDS);
        }
    }
    

    最后是:单线程化线程池

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
     
    public class ThreadPoolDemo {
        public static void main (String[] args) {
            ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
            for(int i = 0; i < 10; i++) {
                final int index = i;
                singleThreadExecutor.execute(new Runnable() {
                    public void run() {
                        try {
                            System.out.println(index);
                            Thread.sleep(2000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } 
                    }
                });
            }
        }
    }
    

    好了四种线程池的使用上面已经介绍完了,现在来看看线程池的原理吧,其中最重要的就是ThreadPoolExecutor类的构造函数,你会有疑惑,上面程序压根没有出现这个ThreadPoolExecutor类

        /**
        *Executors.newSingleThreadExecutor()
        *中查看你会发现如下代码:
        */
        public static ExecutorService newSingleThreadExecutor() {
            return new FinalizableDelegatedExecutorService
                (new ThreadPoolExecutor(1, 1,
                                        0L, TimeUnit.MILLISECONDS,
                                        new LinkedBlockingQueue<Runnable>()));
        }
    

    这四类线程池类底层都是ThreadPoolExecutor类进行初始化的,四大线程池是通过使用ThreadPoolExecutor构造函数实现的:

        public static ExecutorService newCachedThreadPool() {
            return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                          60L, TimeUnit.SECONDS,
                                          new SynchronousQueue<Runnable>());
        }
        public static ExecutorService newFixedThreadPool(int nThreads) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>());
        }
        public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
            return new ScheduledThreadPoolExecutor(corePoolSize);//这边居然不是直接调ThreadPoolExecutor构造函数,但是我们追一下代码看看下面这个函数你就会明白
     
        }
        public ScheduledThreadPoolExecutor(int corePoolSize) {
            super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
                  new DelayedWorkQueue());//里面使用了父类的构造函数,下面就是本类和父类的继承关系,看看他的父类是什么,你就明白了
        }
    
        public class ScheduledThreadPoolExecutor
            extends ThreadPoolExecutor
            implements ScheduledExecutorService 
    

    OK。到这里,你就应该知道我们今天的主角是谁了---------ThreadPoolExecutor
    好了我们可以来看看这个类的构造函数源码了:

         /**
         * 看见有好多参数啊,现在主要对其中的构造参数进行解释:
         * @corePoolSize:核心池大小,意思是当超过这个范围的时候,就需要将新的线程放到等待队列中了即workQueue;
         * @maximumPoolSize:线程池最大线程数量,表明线程池能创建的最大线程数
         * @keepAlivertime:当活跃线程数大于核心线程数,空闲的多余线程最大存活时间。
         * @unit:存活时间的单位
         * @workQueue:存放任务的队列---阻塞队列
         * @handler:超出线程范围(maximumPoolSize)和队列容量的任务的处理程序
         */
        public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue) {
            this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                 Executors.defaultThreadFactory(), defaultHandler);
        }
    

    我们执行线程时都会调用到ThreadPoolExecutor的execute()方法,现在我们来看看这个方法的源码(就是下面这段代码了,这里面有一些注释解析),我直接来解释一下吧:在这段代码中我们至少要看懂一个逻辑:当当前线程数小于核心池线程数时,只需要添加一个线程并且启动它,如果线程数数目大于核心线程池数目,我们将任务放到workQueue中,如果连workQueue满了,那么就要拒绝任务了。详细的函数我就不介绍了

    public void execute(Runnable command) {
            if (command == null)
                throw new NullPointerException();
            /*
             * Proceed in 3 steps:
             *
             * 1. If fewer than corePoolSize threads are running, try to
             * start a new thread with the given command as its first
             * task.  The call to addWorker atomically checks runState and
             * workerCount, and so prevents false alarms that would add
             * threads when it shouldn't, by returning false.
             *
             * 2. If a task can be successfully queued, then we still need
             * to double-check whether we should have added a thread
             * (because existing ones died since last checking) or that
             * the pool shut down since entry into this method. So we
             * recheck state and if necessary roll back the enqueuing if
             * stopped, or start a new thread if there are none.
             *
             * 3. If we cannot queue task, then we try to add a new
             * thread.  If it fails, we know we are shut down or saturated
             * and so reject the task.
             */
            int c = ctl.get();
            if (workerCountOf(c) < corePoolSize) {
                if (addWorker(command, true))
                    return;
                c = ctl.get();
            }
            if (isRunning(c) && workQueue.offer(command)) {
                int recheck = ctl.get();
                if (! isRunning(recheck) && remove(command))
                    reject(command);
                else if (workerCountOf(recheck) == 0)
                    addWorker(null, false);
            }
            else if (!addWorker(command, false))
                reject(command);
        }
    

    相关文章

      网友评论

          本文标题:Android基础 java线程池详解

          本文链接:https://www.haomeiwen.com/subject/lvfcoctx.html