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利用起来了。

原文地址:https://www.cnblogs.com/Xmingzi/p/12601063.html

时间: 2024-10-19 02:48:10

06:线程池的相关文章

线程系列06,通过CLR代码查看线程池及其线程

在"线程系列04,传递数据给线程,线程命名,线程异常处理,线程池"中,我们已经知道,每个进程都有一个线程池.可以通过TPL,ThreadPool.QueueUserWorkItem,委托与线程池交互.本篇体验:通过查看CLR代码来观察线程池及其线程. □ 通过编码查看线程池和线程 使用ThreadPool的静态方法QueueUserWorkItem把线程放入线程池,来看线程池线程和主程序线程的执行情况. class Program { static void Main(string[]

Java多线程系列--“JUC线程池”06之 Callable和Future

概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3544116.html Callable 和 Future 简介 Callable 和 Future 是比较有趣的一对组合.当我们需要获取线程的执行结果时,就需要用到它们.Callable用于产生结果,Future用于获取结果. 1. Callable Calla

Nginx 的线程池与性能剖析

http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt158 正如我们所知,NGINX采用了异步.事件驱动的方法来处理连接.这种处理方式无需(像使用传统架构的服务器一样)为每个请求创建额外的专用进程或者线程,而是在一个工作进程中处理多个连接和请求.为此,NGINX工作在非阻塞的socket模式下,并使用了epoll 和 kqueue这样有效的方法. 因为满负载进程的数量很少(通常每核CPU只有一个)而且恒定,所以任务切换只消耗很少的内

Java - &quot;JUC线程池&quot; Callable与Future

Java多线程系列--"JUC线程池"06之 Callable和Future Callable 和 Future 简介 Callable 和 Future 是比较有趣的一对组合.当我们需要获取线程的执行结果时,就需要用到它们.Callable用于产生结果,Future用于获取结果. 1. Callable Callable 是一个接口,它只包含一个call()方法.Callable是一个返回结果并且可能抛出异常的任务. 为了便于理解,我们可以将Callable比作一个Runnable接

Nginx 的线程池与性能剖析【转载】

正如我们所知,NGINX采用了异步.事件驱动的方法来处理连接.这种处理方式无需(像使用传统架构的服务器一样)为每个请求创建额外的专用进程或者线程,而是在一个工作进程中处理多个连接和请求.为此,NGINX工作在非阻塞的socket模式下,并使用了epoll 和 kqueue这样有效的方法. 因为满负载进程的数量很少(通常每核CPU只有一个)而且恒定,所以任务切换只消耗很少的内存,而且不会浪费CPU周期.通过NGINX本身的实例,这种方法的优点已经为众人所知.NGINX可以非常好地处理百万级规模的并

java线程API学习 线程池ThreadPoolExecutor(转)

线程池ThreadPoolExecutor继承自ExecutorService.是jdk1.5加入的新特性,将提交执行的任务在内部线程池中的可用线程中执行. 构造函数 ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, Rejected

线程复用:线程池

一.核心线程池内部实现 为了能够更好地控制多线程,JDK提供了一套Executor框架,帮助开发人员有效地进行线程控制,其本质就是一个线程池.它的核心成员如图 以上成员均在java.util.concurrent包中,是JDK并发包的核心类.其中ThreadPoolExecutor表示一个线程池.Executors类则扮演着线程池工厂的角色,通过Executors可以取得一个拥有特定功能的线程池. Executor框架提供了各种类型的线程池,主要有以下工厂方法: public static Ex

线程小酌之理解线程池

一.引言 在学习JAVASE部分中,我们都学习到了基本的线程创建继承THREAD类或实现Runnable接口,在正常负载情况下,为每个任务分配一个线程这种方法能够提升串行执行的性能.只要请求的导弹速率不超出服务器的请求处理能力,那么这种方法可以同时带来更快的响应性和更高的吞吐率.但是在实际开发过程中,开发环境和测试环境因数据流量并没有达到实际请求流量,并不能发现实际的问题,在生产环境中,为每个任务分配一个线程这种方法存在一些缺陷,尤其是当需要创建大量的线程时: 1.线程的生命周期的开销非常高 线

NGINX引入线程池 性能提升9倍

1. 引言 正如我们所知,NGINX采用了异步.事件驱动的方法来处理连接.这种处理方式无需(像使用传统架构的服务器一样)为每个请求创建额外的专用进程或者线程,而是在一个工作进程中处理多个连接和请求.为此,NGINX工作在非阻塞的socket模式下,并使用了epoll 和 kqueue这样有效的方法. 因为满负载进程的数量很少(通常每核CPU只有一个)而且恒定,所以任务切换只消耗很少的内存,而且不会浪费CPU周期.通过NGINX本身的实例,这种方法的优点已经为众人所知.NGINX可以非常好地处理百