java线程池使用最全详解

您所在的位置:网站首页 墨池的用法 java线程池使用最全详解

java线程池使用最全详解

2024-07-05 00:27| 来源: 网络整理| 查看: 265

线程池使用 前言

在执行一个异步任务或并发任务时,往往是通过直接new Thread()方法来创建新的线程,这样做弊端较多,更好的解决方案是合理地利用线程池,线程池的优势很明显,如下:

降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗;提高系统响应速度,当有任务到达时,无需等待新线程的创建便能立即执行;方便线程并发数的管控,线程若是无限制的创建,不仅会额外消耗大量系统资源,更是占用过多资源而阻塞系统或oom等状况,从而降低系统的稳定性。线程池能有效管控线程,统一分配、调优,提供资源使用率;更强大的功能,线程池提供了定时、定期以及可控线程数等功能的线程池,使用方便简单。

通用线程工厂:

public static class testThreadPoolFactory implements ThreadFactory { private AtomicInteger threadIdx = new AtomicInteger(0); private String threadNamePrefix; public testThreadPoolFactory(String Prefix) { threadNamePrefix = Prefix; } @Override public Thread newThread(Runnable r) { Thread thread = new Thread(r); thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement()); return thread; } } java线程池

java通过Executors提供四种线程池,分别为:

newCachedThreadPool:

创建一个可缓存的无界线程池,如果线程池长度超过处理需要,可灵活回收空线程,若无可回收,则新建线程。当线程池中的线程空闲时间超过60s,则会自动回收该线程,当任务超过线程池的线程数则创建新的线程,线程池的大小上限为Integer.MAX_VALUE,可看作无限大。

/** * 可缓存无界线程池测试 * 当线程池中的线程空闲时间超过60s则会自动回收该线程,核心线程数为0 * 当任务超过线程池的线程数则创建新线程。线程池的大小上限为Integer.MAX_VALUE, * 可看做是无限大。 */ @Test public void cacheThreadPoolTest() { // 创建可缓存的无界线程池,可以指定线程工厂,也可以不指定线程工厂 ExecutorService executorService = Executors.newCachedThreadPool(new testThreadPoolFactory("cachedThread")); for (int i = 0; i { print("cachedThreadPool"); System.out.println(Thread.currentThread().getName()); } ); } } newFixedThreadPool:

创建一个指定大小的线程池,可控制线程的最大并发数,超出的线程会在LinkedBlockingQueue阻塞队列中等待

/** * 创建固定线程数量的线程池测试 * 创建一个固定大小的线程池,该方法可指定线程池的固定大小,对于超出的线程会在LinkedBlockingQueue队列中等待 * 核心线程数可以指定,线程空闲时间为0 */ @Test public void fixedThreadPoolTest() { ExecutorService executorService = Executors.newFixedThreadPool(5, new testThreadPoolFactory("fixedThreadPool")); for (int i = 0; i < 10; i++) { executorService.submit(() -> { print("fixedThreadPool"); System.out.println(Thread.currentThread().getName()); } ); } } newScheduledThreadPool:

创建一个定长的线程池,可以指定线程池核心线程数,支持定时及周期性任务的执行

/** * 创建定时周期执行的线程池测试 * * schedule(Runnable command, long delay, TimeUnit unit),延迟一定时间后执行Runnable任务; * schedule(Callable callable, long delay, TimeUnit unit),延迟一定时间后执行Callable任务; * scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit),延迟一定时间后,以间隔period时间的频率周期性地执行任务; * scheduleWithFixedDelay(Runnable command, long initialDelay, long delay,TimeUnit unit),与scheduleAtFixedRate()方法很类似, * 但是不同的是scheduleWithFixedDelay()方法的周期时间间隔是以上一个任务执行结束到下一个任务开始执行的间隔,而scheduleAtFixedRate()方法的周期时间间隔是以上一个任务开始执行到下一个任务开始执行的间隔, * 也就是这一些任务系列的触发时间都是可预知的。 * ScheduledExecutorService功能强大,对于定时执行的任务,建议多采用该方法。 * * 作者:张老梦 * 链接:https://www.jianshu.com/p/9ce35af9100e * 来源:简书 * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 */ @Test public void scheduleThreadPoolTest() { // 创建指定核心线程数,但最大线程数是Integer.MAX_VALUE的可定时执行或周期执行任务的线程池 ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5, new testThreadPoolFactory("scheduledThread")); // 定时执行一次的任务,延迟1s后执行 executorService.schedule(new Runnable() { @Override public void run() { print("scheduleThreadPool"); System.out.println(Thread.currentThread().getName() + ", delay 1s"); } }, 1, TimeUnit.SECONDS); // 周期性地执行任务,延迟2s后,每3s一次地周期性执行任务 executorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + ", every 3s"); } }, 2, 3, TimeUnit.SECONDS); executorService.scheduleWithFixedDelay(new Runnable() { @Override public void run() { long start = new Date().getTime(); System.out.println("scheduleWithFixedDelay 开始执行时间:" + DateFormat.getTimeInstance().format(new Date())); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } long end = new Date().getTime(); System.out.println("scheduleWithFixedDelay执行花费时间=" + (end - start) / 1000 + "m"); System.out.println("scheduleWithFixedDelay执行完成时间:" + DateFormat.getTimeInstance().format(new Date())); System.out.println("======================================"); } }, 1, 2, TimeUnit.SECONDS); } newSingleThreadExecutor:

创建一个单线程化的线程池,它只有一个线程,用仅有的一个线程来执行任务,保证所有的任务按照指定顺序(FIFO,LIFO,优先级)执行,所有的任务都保存在队列LinkedBlockingQueue中,等待唯一的单线程来执行任务。

/** * 创建只有一个线程的线程池测试 * 该方法无参数,所有任务都保存队列LinkedBlockingQueue中,核心线程数为1,线程空闲时间为0 * 等待唯一的单线程来执行任务,并保证所有任务按照指定顺序(FIFO或优先级)执行 */ @Test public void singleThreadPoolTest() { // 创建仅有单个线程的线程池 ExecutorService executorService = Executors.newSingleThreadExecutor(new testThreadPoolFactory("singleThreadPool")); for (int i = 0; i { print("singleThreadPool"); System.out.println(Thread.currentThread().getName()); } ); } } 方法对比 工厂方法corePoolSizemaximumPoolSizekeepAliveTimeworkQueuenewCachedThreadPool0Integer.MAX_VALUE60sSynchronousQueuenewFixedThreadPoolnThreadsnThreads0LinkedBlockingQueuenewSingleThreadExecutor110LinkedBlockingQueuenewScheduledThreadPoolcorePoolSizeInteger.MAX_VALUE0DelayedWorkQueue

其他参数都相同,其中线程工厂的默认类为DefaultThreadFactory,线程饱和的默认策略为ThreadPoolExecutor.AbortPolicy。

线程池原理

Executors类提供4个静态工厂方法:newCachedThreadPool()、newFixedThreadPool(int)、newSingleThreadExecutor和newScheduledThreadPool(int)。这些方法最终都是通过ThreadPoolExecutor类来完成的,这里强烈建议大家直接使用Executors类提供的便捷的工厂方法,能完成绝大多数的用户场景,当需要更细节地调整配置,需要先了解每一项参数的意义。

ThreadPoolExecutor public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }

创建线程池,在构造一个新的线程池时,必须满足下面的条件:

corePoolSize(线程池基本大小)必须大于或等于0;maximumPoolSize(线程池最大大小)必须大于或等于1;maximumPoolSize必须大于或等于corePoolSize;keepAliveTime(线程存活保持时间)必须大于或等于0;workQueue(任务队列)不能为空;threadFactory(线程工厂)不能为空,默认为DefaultThreadFactory类handler(线程饱和策略)不能为空,默认策略为ThreadPoolExecutor.AbortPolicy。 参数详解 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3