zoukankan      html  css  js  c++  java
  • 06:线程池

    1:线程池原理-基本概念:
        1:线程池管理器:用户管理线程池。包括创建线程池、销毁线程池,添加新任务等。
        2:工作线程:工作线程就是线程池中实际工作的线程。没有任务时:处于等待状态,有任务时:可以循环的执行任务。
        3:任务接口:每个任务都需要实现的接口。规范了任务的输入、输出等。
        4:任务队列:任务太多时,超过了线程池处理能力。将待处理的任务放到等待队列中。
    2:线程池接口和实现类:
        1:接口:Executor:最上层的接口:定义了执行任务的方法:executor()
        2:接口:ExecutorService:继承了Executor接口,扩展了Callable,Future,关闭方法。
        3:接口:ScheduledExecutorService:继承了ExecutorService,怎加了定时任务相关的方法。
        4:实现类:ThreadPoolExecutor:标准的线程池实现。但是比较基础。
        5:实现类:ScheduledThreadPoolExecutor:继承了ThreadPoolExecutor,实现了ScheduledExecutorService。也就是说:在标准的线程池类基础上怎加了定时任务。

    3:ThreadPoolExecutorc测试:

    /**
     *  1:核心线程数量5,最大数量10,无界队列,超出核心线程数量的线程存活时间5秒。
     */                                                       // 没有达到线程池最大线程数量10,而是进入了等待队列。
    private static void threadPoolExecutorTest1() throws Exception{                    当前线程池线程数量为:5
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(                  当前线程池等待队列的长度:5     
                5, // 核心线程数量                                       线程结束:7
                10, // 最大线程数量                                       ...
                5, // 超出核心线程数量的线程的存活时间                            线程结束:14
                TimeUnit.SECONDS, // 单位                                   当前线程池线程数量为:5
                new LinkedBlockingQueue<Runnable>()); // 线程等待队列                   当前线程池等待队列的长度:0
        testCommon(threadPoolExecutor);                                    // 因为没有把队列占满,只有等待队列满了才会超出核心线程数量
    }
    /**
     *  1:等待队列长度为3,2: 指定拒绝策略。
     */ 
    private static void threadPoolExecutorTest2() throws Exception{
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                5, 10, 5, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(3),                             等待队列调小为3               
                new RejectedExecutionHandler() {                                        // 如果(等待队列满了 && 最大线程数量也达到了):执行拒接策略
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                        System.out.println("任务被拒绝执行。");
                    }
                }
        );
        testCommon(threadPoolExecutor);
    }
    /**
     * 1:核心线程数量 = 最大线程数 , 队列无界
     */
    private static void threadPoolExecutorTest3()throws Exception{
        // 和线程池工具类的 Executors.newFixedThreadPool(int nThreads)实现一样。        // 和Executors.newFixedThreadPool(int nThreads)实现一样
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                5, 5, 5, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>()
        );
        testCommon(threadPoolExecutor);
    }
    /**
     * SynchronousQueue,实际上不是一个真正的队列,因为他不会为队列中的元素维护存储空间。他维护的是一组线程。
     * 这种线程池起初没有线程,最后执行完成后也没有线程。
     * 60秒后无用的线程就会销毁
     */
    private static void threadPoolExecutorTest4() throws Exception{                // 和Executors.newCachedThreadPool() 实现一样
        // 和 Executors.newCachedThreadPool() 方法一样                       // 当无法预估需要多少线程,但是最大线程数量自己设定。不然太大了。
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(0,Integer.MAX_VALUE, 60L,TimeUnit.SECONDS,   // 如果运行过程中有线程,就复用。没有就加开。     
                new SynchronousQueue<Runnable>());                            // 不工作的线程,60秒后自动销毁。
    }                                                     //  注意控制最大线程数量。
    /**
     * 定时执行 : 3秒后执行,一次性执行,到时间就执行。
     *           核心线程数:5 , 最大线程数为:Integer.MAX_VALUE
     *           DelayedWorkQueue 为延时队列,存放进去一定时间后才可以取出来。
     * @throws Exception
     */
    private static void threadPoolExecutorTest5() throws Exception{                // 定时任务,延时执行一次。
        // Executors.newScheduledThreadPool()
        ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(5);    // 如果你的任务需要很多线程,就调多一点。
        scheduledThreadPoolExecutor.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("任务执行");
            }
        },
        3000,
        TimeUnit.MICROSECONDS);        // 3秒之后执行
    }
    /**
     * 定时任务,周期性执行。(固定频率,固定延迟)
     * 固定线程数:5 核心线程数5 最大线程数Integer.MAX_VALUE 延时队列,超出核心线程数量的线程存活0秒。
     * 例如:需要定时查询数据库的任务。
     */
    private static void threadPoolExecutorTest6() throws Exception{
        // 周期性执行任务有两种调度方式。
        ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
        // 第一种:固定频率:提交后:2秒后开始第一次执行,之后每间隔一秒,固定执行一次。(如果发现上次任务未完成,等待完毕后立即执行下一个任务)
        threadPoolExecutor.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                    System.out.println("如果任务执行时间超出了周期时间,下一个任务直接开始");
            }
        },2000 , 1000 ,TimeUnit.MICROSECONDS);
        // 第二种:固定延迟:提交后:两秒后开始第一次执行,之后每间隔一秒,固定执行一次。(如果发现上次任务未完毕,等上一次完毕后,再等待一秒。然后执行下一个任务)
        threadPoolExecutor.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                System.out.println("如果任务执行时间超出了周期时间,下一个任务重新计算执行延时后再执行");
            }
        },2000,1000,TimeUnit.MICROSECONDS);
    }
    /**
     * 测试:提交15个执行时间为3秒的任务。并输出线程状态。
     * @param threadPoolExecutor 显示池
     */
    private static void testCommon(ThreadPoolExecutor threadPoolExecutor)throws Exception{
        for (int i = 0; i < 15; i++) {
            int n = i;
            threadPoolExecutor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("开始时间:"+n);
                        Thread.sleep(3000L);
                        System.out.println("线程结束:"+n);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            System.out.println("任务提交成功"+i);
        }
        // 等待5秒后看线程池状态
        Thread.sleep(5000L);
        System.out.println("当前线程池线程数量为:"+threadPoolExecutor.getPoolSize());
        System.out.println("当前线程池等待队列的长度:"+threadPoolExecutor.getQueue().size());
        // 等待15秒,查看线程池状态(理论上,超出核心线程数量的线程会被销毁)
        Thread.sleep(10000L);
        System.out.println("当前线程池线程数量为:"+threadPoolExecutor.getPoolSize());
        System.out.println("当前线程池等待队列的长度:"+threadPoolExecutor.getQueue().size());
    }

     4:可以用线程池工具类快速创建线程池:

    5:如何合适的定义线程池的线程数量:
        1:计算型任务(计算数据任务):线程的数量是CPU熟练的 1~2倍即可。
        2:IO型任务(网络操作,数据库操作,文件操作):根据具体的IO阻塞时长考量。就是说阻塞的时候开多线程执行。
        3:考虑设置最小的线程数量和最大线程数量。自动在这个区间怎加线程数量。
        4:窍门:通过监控CPU的使用率。达到80%就说明cpu利用起来了。
  • 相关阅读:
    WP7 操作XML文件
    C#和C/C++指针实现swap交换
    感受
    我学到了什么&nbsp;我思考了什么.
    hdu 2768 Cat vs. Dog (最大独立)
    hdu 1960 Taxi Cab Scheme (最小覆盖)
    hdu 1528 Card Game Cheater (最小覆盖)
    hdu 4160 Dolls (最大独立)
    hdu 2458 Kindergarten (最大独立集)
    hdu 2119 Matrix (最小覆盖)
  • 原文地址:https://www.cnblogs.com/Xmingzi/p/12601063.html
Copyright © 2011-2022 走看看