java进程池详解
原创1.使用线程池的好处
- 减少资源消耗:通过重用已创建的线程,减少线程创建和销毁的损失。
- 提高响应速度:当线程池中的线程数不超过线程池的最大上限时,一些线程正在等待分配任务,并且可以在任务到来时在不创建新线程的情况下执行。
- 提高线程的可管理性:线程池将根据当前系统的特性优化池中的线程,并使用线程池统一分配线程,这可以避免无线创建和破坏线程,提高资源利用率和系统稳定性。
2.创建线程池的常用方法
- 通过Executors工厂方法创建。
- 通过new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long
keepAliveTime, TimeUnit unit, BlockingQueue
workQueue)自定义创建。
三、详解Executors工厂方法创建
-
newCachedThreadPool:创建可缓存线程池。如果线程池的长度超过了处理要求,则可以灵活地回收空闲线程。如果没有回收,可以创建新线程。
ExecutorService es3 = Executors.newCachedThreadPool(); for (int i = 0; i < 20; i++) { es3.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + "任务正在进行"); } }); }
-
newFixedThreadPool:创建固定长度的线程池以控制并发线程的最大数量。超过的线程将在屏障中等待。
ExecutorService es2 = Executors.newFixedThreadPool(3); for (int i = 0; i < 10; i++) { es2.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + "任务正在进行"); } }); }
-
newScheduledThreadPool:创建固定长度的线程池。支持固定和周期性人员实施。
ScheduledExecutorService es4 = Executors.newScheduledThreadPool(2); System.out.println("时间:" + System.currentTimeMillis()); for (int i = 0; i < 5; i++) { es4.schedule(new Runnable() { @Override public void run() { System.out.println("时间:"+System.currentTimeMillis()+"--"+Thread.currentThread().getName() + "任务正在进行"); } },3, TimeUnit.SECONDS); }
-
newSingleThreadExecutor:创建一个仅使用唯一工作线程执行任务的单线程线程池,以保证所有任务。
ExecutorService es1 = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { es1.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + "任务正在进行"); } }); }
注:请参阅阿里巴巴开发手册并发编程Executors创建,但ThreadPoolExecutor方法原因是在线程溢出的情况下,很容易导致OOM异常(OOM:内存溢出)、资源耗尽。
四、详解ThreadPoolExecutor自定义创建
建议以这种方式创建线程池,并且创建的线程池没有缺点,Executors底层是ThreadPoolExecutor。
-
如何创建:
new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue
workQueue) -
七个参数的详细说明:
(1)corePoolSize[5]:核心线程数,始终存在的线程数,除非。allowCoreThreadTimeOut。创建线程池后准备就绪的线程数,等待接收要执行的异步任务。相等的5个 Thread thread = new Thread(); thread.start();
(2)maximumPoolSize[200]:最大线程数,指定线程池中的最大线程数并控制资源。
(3)keepAliveTime:生存时间。如果当前运行的线程数大于core释放空闲线程的数量(maximumPoolSize-corePoolSize),只要线程空闲时间大于指定的keepAliveTime。
(4)unit:时间单位。
(5)BlockingQueue< Runnable > workQueue:阻塞队列。如果有许多任务,许多任务将被放置在队列中。只要有线程空闲,新任务就会从队列中取出以继续执行。
(6)ThreadFactory:线程创建的工厂。
(7)RejectedExecutionHandler handler:如果队列已满,请根据我们指定的拒绝策略拒绝执行。
- 工作顺序和流程
(1)线程池创建,就绪corePoolSize准备接受任务的核心线程数;
(2)核心线程已全部使用,再次进入的任务被放入阻塞队列(BlockingQueue). 空闲的核心线程将阻塞队列以自行获得任务执行;
(3当阻塞队列已满时,新线程将直接打开执行,并且只能打开最大线程数(maximumPoolSize)螺纹数量;
(4最大线程数已满。RejectedExecutionHandler拒绝任务;
(5执行的线程最大,在指定的时间有大量空闲。keepAliveTime之后,释放空闲线程。(max-core)。
-
举个栗子
线程池 core 7, max 20, queue 50, 100它进来时是如何分配的?ThreadPoolExecutor executor = new ThreadPoolExecutor( 5, 200, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100000), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
答:7将立即执行。50进入开放式队列。13要执行的线程,剩下30一种是使用拒绝策略。
版权声明
所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除