一、使用线程池的优点:
1、线程重用,避免线程创建的开销
2、任务过多时,通过队列避免创建过多线程,减少系统资源消耗和竞争,确保任务有序完成
二、如何使用线程池:
1、ThreadPoolExecutor 构造方法:
public class ThreadPoolExecutorTest { public static void main(String[] args){ int num = 10; ArrayBlockingQueue<Runnable> arrayBlockingQueue = new ArrayBlockingQueue<>(num); RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy(); ThreadFactory threadFactory = new MyThreadFactory(); /** * corePoolSize:核心线程个数 * maximumPoolSize:最大线程个数 * keepAliveTime、unit:空闲线程存活时间 * workQueue:指定工作队列,要求是阻塞队列 * 常用的阻塞队列类型: * LinkedBlockingQueue:基于链表的阻塞队列,可以指定最大长度,但默认是无界的 * ArrayBlockingQueue:基于数组的有界阻塞队列 * PriorityBlockingQueue:基于堆的无界阻塞优先级队列 * SynchronousQueue:没有实际存储空间的同步阻塞队列 */ ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 10, 10, TimeUnit.SECONDS, arrayBlockingQueue, threadFactory, rejectedExecutionHandler ); } static class MyThreadFactory implements ThreadFactory{ private static final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; MyThreadFactory() { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-"; } public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); if (t.isDaemon()) t.setDaemon(false); if (t.getPriority() != Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY); return t; } } }
2、任务拒绝策略:如果队列有界,且maximumPoolSize有限,则当队列排满,线程个数也达到了maximumPoolSize,这时,新任务来了,会触发线程池的任务拒绝策略。
默认情况下,提交任务的方法(execute / submit / invokeAll)会抛RejectedExecutionException 异常。
3、RejectedExecutionHandler 自定义拒绝策略的四种方式:
1)ThreadPoolExecutor.AbortPolicy 默认的方式,抛出异常;
2)ThreadPoolExecutor.DiscardPolicy 静默处理,忽略新任务,不跑处异常,也不执行;
3)ThreadPoolExecutor.DiscardOldestPolicy 将等待时间最长的任务扔掉,然后自己排队;
4)ThreadPoolExecutor.CallerRunsPoliy 在任务提交者线程中执行任务,而不是交给线程池中的线程执行;
4、ThreadFactory 线程工厂:
1)ThreadPoolExecutor的默认实现是Executors类中的静态内部类DefaultThreadFactory,主要就是创建一个线程,给线程设置一个名称,设置daemon为false,设置线程优先级为标准默认优先级,以及线程名称。
源码如下:
/** * The default thread factory */ static class DefaultThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; DefaultThreadFactory() { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-"; } public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); if (t.isDaemon()) t.setDaemon(false); if (t.getPriority() != Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY); return t; } }
5、关于核心线程的特殊配置:核心线程不会预先创建,只有当有任务时才会创建,核心线程不会因为空闲而被终止,keepAliveTime参数不适应于它。
三、Executors 工厂类:
Executors 提供了一些静态工厂方法,可以方便地创建一些预配置的线程池,主要方法有:
1、newSingleThreadExecutor() 只使用一个线程,使用无界队列LinkedBlockingQueue,线程创建后不会超时终止,该线程顺序执行所有任务。该线程适用于需要确保所有任务被顺序执行的场合;
2、newFixedThreadPool(int nThread) 使用固定数目的n个线程,使用无界队列LinkedBlockingQueue,线程创建后不会超时终止。和newSingleThreadExecutor一样,由于是无界队列,如果排队任务过多,可能会消耗过多的内存;
3、newCachedThreadPool() 它的corePoolSize 为0,maximumPoolSize 为Integer.MAX_VALUE,keepAliveTime 是60秒,队列为SynchronousQueue。当新任务到来时,如果正好有空闲线程在等待任务,则其中一个空闲线程接受该任务,否则就总是创建一个新线程,创建的总线程个数不受限制,对任一空线程,如果60秒内没有新任务,就终止。
代码实例:
public static void executorsDemo(){ ExecutorService executorService = Executors.newSingleThreadExecutor(); executorService = Executors.newFixedThreadPool(10); executorService = Executors.newCachedThreadPool(); executorService.submit(new Runnable() { @Override public void run() { System.out.println("Executors 工具类"); } }); executorService.shutdown(); }
原文:https://www.cnblogs.com/haiyangwu/p/10445584.html