zoukankan      html  css  js  c++  java
  • Java线程池入门必备

    线程池

    一. 线程池的简介

    1.什么是线程池?

      最早期的工作线程处理任务的模型。一个任务的到来,会伴随着线程的创建,当处理完任务后,线程会被销毁,资源回收。这种一个任务一个线程一系列创建销毁的模式,缺陷毋庸置疑.不仅是线程创建销毁带来的系统开销,也不好管理工作线程。于是引入了“线程池”的概念。它是一种预创建线程的技术。每次线程执行完任务前,先把任务委派给线程池空闲的线程, 如果没有空闲的线程, 则根据线程池任务策略执行。处理完任务后, 线程不会直接被销毁掉,会放到线程池管理。

    2.线程池有何作用?

      线程池的作用, 个人理解主要有三点。

    • 减少系统资源的开销 :避免新线程的创建、销毁等繁琐过程。

    • 提供系统的性能 : 池至少有一个以上的线程, 多线程协同工作, 可响应多个客户端请求。而且可以重复利用池里空闲的线程,免去了新线程不断地创建、销毁过程.

    • 提高系统稳定性 :一个请求一个线程处理, 高并发请求下, 系统不得不创建大量线程来接活。大量的线程创建、销毁会占用系统大量资源, 最终耗光系统资源, 导致系统宕机。引入线程池后,能根据系统的承载能力, 调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

    二. 线程池的创建

    线程池的创建入口Executors.真正干活的是ExecutorService

    1. newFixedThreadPool
    • 说明

      创建固定大小的线程池。每次提交一个任务,就会启一个线程来接客,直到线程池的线程数量达到线程池的上限。

    • demo
    public class PoolDemo {
    
        public static void main(String[] args) {
            ExecutorService executorService = Executors.newFixedThreadPool(2);
    
            for(int i = 0; i<5; i++) {
    
                executorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(Thread.currentThread().getName());
                    }
                });
            }
    
            executorService.shutdown();
        }
    }
    result :
    pool-1-thread-1
    pool-1-thread-2
    pool-1-thread-1
    pool-1-thread-2
    pool-1-thread-1
    
    1. newCachedThreadPool
    • 说明

       创建一个可缓存的线程池。每次提交一个任务,委派给线程池空闲的线程处理, 如果木有空闲的线程, 则直接创建新线程,任务被执行完后,当前线程加入到线程池维护。其生命周期超过一定时间会被销毁回收。

    • demo
    
    public class PoolDemo {
    
        public static void main(String[] args) {
            ExecutorService executorService = Executors.newCachedThreadPool();
    
            for(int i = 0; i<5; i++) {
    
                executorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(Thread.currentThread().getName());
                    }
                });
            }
    
            executorService.shutdown();
        }
    }
    result:
    pool-1-thread-1
    pool-1-thread-2
    pool-1-thread-4
    pool-1-thread-3
    pool-1-thread-5
    
    1. newSingleThreadExecutor
    • 说明

      创建只有一个线程的线程池。问题来了, 一个线程的线程池和普通创建一个线程一样么?当然不一样.线程销毁问题。

    • demo
    public class PoolDemo {
    
        public static void main(String[] args) {
            ExecutorService executorService = Executors.newSingleThreadExecutor();
    
            for(int i = 0; i<5; i++) {
    
                executorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(Thread.currentThread().getName());
                    }
                });
            }
    
            executorService.shutdown();
        }
    }
    
    result:
    pool-1-thread-1
    pool-1-thread-1
    pool-1-thread-1
    pool-1-thread-1
    pool-1-thread-1
    
    1. newScheduledThreadPool
    • 说明

       创建一个大小不受限的线程池。提供定时、周期地执行任务能力。

    • demo
    public class PoolDemo {
    
        public static void main(String[] args) {
            ExecutorService executorService = Executors.newScheduledThreadPool(2);
    
            for(int i = 0; i<5; i++) {
    
                executorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(Thread.currentThread().getName());
                    }
                });
            }
    
            executorService.shutdown();
        }
    }
    
    result:
    pool-1-thread-1
    pool-1-thread-1
    pool-1-thread-1
    pool-1-thread-2
    pool-1-thread-1
    
    • 定时周期执行demo2
    public class PoolDemo {
    
        public static void main(String[] args) {
            ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
    
            long initialDelay = 1, delay = 1;
            
            // 应用启动1S后,每隔1S执行一次
            
            executorService.scheduleWithFixedDelay(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            }, initialDelay, delay, TimeUnit.SECONDS);
    
            // 应用启动1S后,每隔2S执行一次
            executorService.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            }, initialDelay, delay, TimeUnit.SECONDS);
        }
    }
    

    拓展scheduleWithFixedDelay | scheduleAtFixedRate 区别 看下源码注释

    • scheduleAtFixedRate
        /**
         * Creates and executes a periodic action that becomes enabled first
         * after the given initial delay, and subsequently with the given
         * period; that is executions will commence after
         * {@code initialDelay} then {@code initialDelay+period}, then
         * {@code initialDelay + 2 * period}, and so on.
         * If any execution of the task
         * encounters an exception, subsequent executions are suppressed.
         * Otherwise, the task will only terminate via cancellation or
         * termination of the executor.  If any execution of this task
         * takes longer than its period, then subsequent executions
         * may start late, but will not concurrently execute.
         *
         * @param command the task to execute
         * @param initialDelay the time to delay first execution
         * @param period the period between successive executions
         * @param unit the time unit of the initialDelay and period parameters
         * @return a ScheduledFuture representing pending completion of
         *         the task, and whose {@code get()} method will throw an
         *         exception upon cancellation
         * @throws RejectedExecutionException if the task cannot be
         *         scheduled for execution
         * @throws NullPointerException if command is null
         * @throws IllegalArgumentException if period less than or equal to zero
         */
        public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                      long initialDelay,
                                                      long period,
                                                      TimeUnit unit);
    
    • scheduleWithFixedDelay
    /**
         * Creates and executes a periodic action that becomes enabled first
         * after the given initial delay, and subsequently with the
         * given delay between the termination of one execution and the
         * commencement of the next.  If any execution of the task
         * encounters an exception, subsequent executions are suppressed.
         * Otherwise, the task will only terminate via cancellation or
         * termination of the executor.
         *
         * @param command the task to execute
         * @param initialDelay the time to delay first execution
         * @param delay the delay between the termination of one
         * execution and the commencement of the next
         * @param unit the time unit of the initialDelay and delay parameters
         * @return a ScheduledFuture representing pending completion of
         *         the task, and whose {@code get()} method will throw an
         *         exception upon cancellation
         * @throws RejectedExecutionException if the task cannot be
         *         scheduled for execution
         * @throws NullPointerException if command is null
         * @throws IllegalArgumentException if delay less than or equal to zero
         */
        public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                         long initialDelay,
                                                         long delay,
                                                         TimeUnit unit);
    

    不难得出如下结论:

    ScheduledExecutorService 中两种最常用的调度方法 ScheduleAtFixedRate 和 
    ScheduleWithFixedDelay。ScheduleAtFixedRate 
    每次执行时间为上一次任务开始起向后推一个时间间隔,即每次执行时间为 
    :initialDelay, initialDelay+period, initialDelay+2*period, 
    …;ScheduleWithFixedDelay 
    每次执行时间为上一次任务结束起向后推一个时间间隔,即每次执行时间为:initialDela
    y, initialDelay+executeTime+delay, 
    initialDelay+2*executeTime+2*delay。由此可见,ScheduleAtFixedRate 
    是基于固定时间间隔进行任务调度,ScheduleWithFixedDelay 
    取决于每次任务执行的时间长短,是基于不固定时间间隔进行任务调度。
    

    三. 线程池的拒绝策略

      线程池的拒绝策略是干嘛来的?它是在应接不暇的时候, 对新任务采取的执行策略(执行?丢弃and so on). RejectedExecutionHandler是拒绝任务策略的基础接口, Jdk提供了四种拒绝策略。

    1.CallerRunsPolicy

      这种策略是说线程池在没被关闭前, 直接会去执行此任务, 否则丢弃任务。

        /**
         * A handler for rejected tasks that runs the rejected task
         * directly in the calling thread of the {@code execute} method,
         * unless the executor has been shut down, in which case the task
         * is discarded.
         */
        public static class CallerRunsPolicy implements RejectedExecutionHandler {
            /**
             * Creates a {@code CallerRunsPolicy}.
             */
            public CallerRunsPolicy() { }
    
            /**
             * Executes task r in the caller's thread, unless the executor
             * has been shut down, in which case the task is discarded.
             *
             * @param r the runnable task requested to be executed
             * @param e the executor attempting to execute this task
             */
            public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                if (!e.isShutdown()) {
                    r.run();
                }
            }
        }
    

    2.AbortPolicy

      AbortPolicy线程拒绝策略,简单粗暴, 直接throw exception出来了, 丢弃任务

        /**
         * A handler for rejected tasks that throws a
         * {@code RejectedExecutionException}.
         */
        public static class AbortPolicy implements RejectedExecutionHandler {
            /**
             * Creates an {@code AbortPolicy}.
             */
            public AbortPolicy() { }
    
            /**
             * Always throws RejectedExecutionException.
             *
             * @param r the runnable task requested to be executed
             * @param e the executor attempting to execute this task
             * @throws RejectedExecutionException always
             */
            public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                throw new RejectedExecutionException("Task " + r.toString() +
                                                     " rejected from " +
                                                     e.toString());
            }
        }
    

    3.DiscardPolicy

      DiscardPolicy策略跟AbortPolicy一样, 直接丢弃任务, 只不过人家不抛出exception罢了。

        /**
         * A handler for rejected tasks that silently discards the
         * rejected task.
         */
        public static class DiscardPolicy implements RejectedExecutionHandler {
            /**
             * Creates a {@code DiscardPolicy}.
             */
            public DiscardPolicy() { }
    
            /**
             * Does nothing, which has the effect of discarding task r.
             *
             * @param r the runnable task requested to be executed
             * @param e the executor attempting to execute this task
             */
            public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            }
        }
    

    4.DiscardOldestPolicy

      DiscardOldestPolicy策略, 是在线程池没被关闭的情况下, 丢弃任务等待队列中最早的任务。然后重新尝试运行该任务。

        /**
         * A handler for rejected tasks that discards the oldest unhandled
         * request and then retries {@code execute}, unless the executor
         * is shut down, in which case the task is discarded.
         */
        public static class DiscardOldestPolicy implements RejectedExecutionHandler {
            /**
             * Creates a {@code DiscardOldestPolicy} for the given executor.
             */
            public DiscardOldestPolicy() { }
    
            /**
             * Obtains and ignores the next task that the executor
             * would otherwise execute, if one is immediately available,
             * and then retries execution of task r, unless the executor
             * is shut down, in which case task r is instead discarded.
             *
             * @param r the runnable task requested to be executed
             * @param e the executor attempting to execute this task
             */
            public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                if (!e.isShutdown()) {
                    e.getQueue().poll();
                    e.execute(r);
                }
            }
        }
    

    写在最后

    新博客请移步

  • 相关阅读:
    前端开发面试题总结之——HTML
    HashMap的那些事
    抽象同步队列AQS(中)—— AQS的重点方法解析
    抽象同步队列AQS(上)—— 宏观上理解AQS
    synchronized原理详解
    volatile原理详解
    JMM模型详解
    计算机运行时内存&处理器CPU初步认知
    mysql-索引详解
    mysql-事务隔离机制&mvcc原理
  • 原文地址:https://www.cnblogs.com/chenmo-xpw/p/7059782.html
Copyright © 2011-2022 走看看