《阿里巴巴java开发手册》
线程池不使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样 的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
主要原因是使用Executors创建线程池不会传入这个参数而使用默认值所以我们常常忽略这一参数,而且默认使用的参数会导致资源浪费,不可取。
说明: Executors 返回的线程池对象的弊端如下:
1.FixedThreadPool 和 SingleThreadPool : 允许的请求队列长度为 Integer.MAX_VALUE ,可能会堆积大量的请求,从而导致 OOM 。
2.CachedThreadPool 和 ScheduledThreadPool : 允许的创建线程数量为 Integer.MAX_VALUE ,可能会创建大量的线程,从而导致 OOM 。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
应用
RunnableTask.java
package com.person.threadpool; /** * 任务类 :实现Runnable */ public class RunnableTask implements Runnable{ private int num; public RunnableTask(int num){ this.num = num; } @Override public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } String threadName = Thread.currentThread().getName(); String msg = "当前线程名 ["+threadName+"] 执行任务 [RunnableTask"+num+"] Done"; System.out.println(msg); } }
ExecutorsnewSingleThreadExecutorTest.java
package com.person.threadpool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ExecutorsnewSingleThreadExecutorTest { public static void main(String[] args) throws Exception{ //线程池中只有一个线程,保证所有任务的执行顺序按照任务的提交顺序执行。 //如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。 ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor(); // 提交多个任务 for (int i = 1; i <= 10; i++) { RunnableTask task = new RunnableTask(i);// 任务 newSingleThreadExecutor.submit(task); } //主线程休眠,确保任务都执行完成再关闭线程池 Thread.currentThread().sleep(1000); newSingleThreadExecutor.shutdown();// 关闭线程池,如果还是线程没有执行完成则会继续执行,只是之后不能添加新的任务 } }
ExecutorsnewFixedThreadPoolTest.java
package com.person.threadpool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ExecutorsnewFixedThreadPoolTest { public static void main(String[] args) { // 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。 //线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。 ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(3); // 提交多个任务 for (int i = 1; i <= 10; i++) { RunnableTask task = new RunnableTask(i);// 任务 newFixedThreadPool.submit(task); } newFixedThreadPool.shutdown();// 关闭线程池,如果还是线程没有执行完成则会继续执行,只是之后不能添加新的任务 } }
ExecutorsnewCachedThreadPoolTest.java
package com.person.threadpool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ExecutorsnewCachedThreadPoolTest { public static void main(String[] args) throws Exception{ /*创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程, *那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。 *此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。 */ ExecutorService newCachedThreadPool = Executors.newCachedThreadPool(); //提交多个任务 for(int i=1;i<=10;i++){ RunnableTask task = new RunnableTask(i);//任务 newCachedThreadPool.submit(task); } //主线程暂停,确保执行后面的任务时,前面的任务全部执行完成 Thread.currentThread().sleep(4000); System.out.println("=========================================="); //重新让线程池执行任务,可以发现 线程池中的线程被重复利用 for(int i=11;i<=20;i++){ RunnableTask task = new RunnableTask(i);//任务 newCachedThreadPool.submit(task); } //主线程休眠,确保任务都执行完成再关闭线程池 Thread.currentThread().sleep(1000); //关闭线程池 newCachedThreadPool.shutdown(); } }
ExecutorsnewScheduledThreadPoolTest.java
package com.person.threadpool; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class ExecutorsnewScheduledThreadPoolTest { public static void main(String[] args) { //创建一个定长线程池,支持定时及周期性任务执行 ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(3); //延迟执行任务 RunnableTask task = new RunnableTask(1);//任务 newScheduledThreadPool.schedule(task, 3, TimeUnit.SECONDS); //也可以接收一个Callable实现类任务 //周期性任务:延迟3秒执行第一次,每10秒执行一次,不关心上一次是否执行完成 RunnableTask periodTask = new RunnableTask(4);//任务 newScheduledThreadPool.scheduleAtFixedRate(periodTask, 3, 10, TimeUnit.SECONDS); //延迟3秒执行第一次任务,第一次执行完成再延迟10秒执行第二次,第二次执行完成再延迟10秒执行第三次.... RunnableTask fixedDelayTask = new RunnableTask(8);//任务 newScheduledThreadPool.scheduleWithFixedDelay(fixedDelayTask, 3, 10, TimeUnit.SECONDS); //newScheduledThreadPool.shutdown(); //当执行周期性任务时,不能关闭线程池,否则任务不被执行。 } }