在创建线程之前,我们要先熟悉一个类Thread;
public class Thread implements Runnable { /* Make sure registerNatives is the first thing <clinit> does. */ private static native void registerNatives(); static { registerNatives(); } /*省略一堆*/ /** * If this thread was constructed using a separate * <code>Runnable</code> run object, then that * <code>Runnable</code> object's <code>run</code> method is called; * otherwise, this method does nothing and returns. * <p> * Subclasses of <code>Thread</code> should override this method. * * @see #start() * @see #stop() * @see #Thread(ThreadGroup, Runnable, String) */ @Override public void run() { if (target != null) { target.run(); } } }重写的Runnable接口的run方法,为业务运行代码编写的地方,如果我们要实现业务书写,也需要重写run方法,再通过点start方法启动线程,等待CPU调用!
这里重点讲解线程池之前,简单过一下main中,使用线程的几种方式!
首先我们来看看线程池的构造函数:
// Public constructors and methods /** * Creates a new {@code ThreadPoolExecutor} with the given initial * parameters and default thread factory and rejected execution handler. * It may be more convenient to use one of the {@link Executors} factory * methods instead of this general purpose constructor. * * @param corePoolSize the number of threads to keep in the pool, even * if they are idle, unless {@code allowCoreThreadTimeOut} is set * @param maximumPoolSize the maximum number of threads to allow in the * pool * @param keepAliveTime when the number of threads is greater than * the core, this is the maximum time that excess idle threads * will wait for new tasks before terminating. * @param unit the time unit for the {@code keepAliveTime} argument * @param workQueue the queue to use for holding tasks before they are * executed. This queue will hold only the {@code Runnable} * tasks submitted by the {@code execute} method. * @throws IllegalArgumentException if one of the following holds: * {@code corePoolSize < 0} * {@code keepAliveTime < 0} * {@code maximumPoolSize <= 0} * {@code maximumPoolSize < corePoolSize} * @throws NullPointerException if {@code workQueue} is null */ public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }我们通过这个图,来理解里面的几个参数: 第一个参数:int corePoolSize 核心线程,上图绿色方框中的内容! 第二个参数:int maximumPoolSize 最大线程,核心线程和非核心线程的总数! 第三个参数:long keepAliveTime 存活时间,非核心线程的存活时间! 第四个参数:TimeUnit unit 存活时间单位,来自JUC中的TimeUnit枚举类! 第五个参数:BlockingQueue workQueue 阻塞队列 可以new 它的实现类,作为这个参数,配置上对应的长度即可 比如:new ArrayBlockingQueue(5) 长度五的阻塞队列! 第六个参数:RejectedExecutionHandler handler 异常处理方式,为红色部分所示!具体使用方式如下图所示,使用例子:new ThreadPoolExecutor.DiscardOldestPolicy()“丢弃老任务(队头)策略”
package com.woniuxy.concurrent.executor; import java.util.concurrent.*; /** * Auther: mayuhang <br/> * Date: 2020/6/15:9:36 <br/> * Description:线程池创建 */ public class ExecutorPoolTest1 { static int j = 0; public static void main(String[] args) { /** * Auther: mayuhang <br/> * Date: 15:19:2020/7/6 <br/> * Description: 表示核心线程5个,总线程数量10个,非核心线程5个存活时间为5000微秒, * 使用 new ArrayBlockingQueue<Runnable>(5)队列,队列容量5,可以放入5个待执行任务, * 异常处理方式为new ThreadPoolExecutor.AbortPolicy() 抛出异常! */ ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5000, TimeUnit.MICROSECONDS, new ArrayBlockingQueue<>(5), new ThreadPoolExecutor.AbortPolicy()); for (int i = 1; i <= 16; i++) { threadPoolExecutor.submit(new Runnable() { @Override public void run() { System.out.println("我是"+Thread.currentThread().getName()+"线程,正在执行" + (++ExecutorPoolTest1.j) + "的任务!"); try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } } },i); } } } 打印结果: 我是pool-1-thread-1线程,正在执行1的任务! 我是pool-1-thread-4线程,正在执行4的任务! 我是pool-1-thread-2线程,正在执行2的任务! 我是pool-1-thread-3线程,正在执行3的任务! 我是pool-1-thread-5线程,正在执行5的任务! 我是pool-1-thread-6线程,正在执行6的任务! 我是pool-1-thread-7线程,正在执行7的任务! 我是pool-1-thread-8线程,正在执行8的任务! 我是pool-1-thread-9线程,正在执行9的任务! 我是pool-1-thread-10线程,正在执行10的任务! Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@5cad8086 rejected from java.util.concurrent.ThreadPoolExecutor@6e0be858[Running, pool size = 10, active threads = 10, queued tasks = 5, completed tasks = 0] at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047) at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823) at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369) at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:123) at com.woniuxy.concurrent.executor.ExecutorPoolTest1.main(ExecutorPoolTest1.java:25) 我是pool-1-thread-7线程,正在执行11的任务! 我是pool-1-thread-4线程,正在执行13的任务! 我是pool-1-thread-10线程,正在执行12的任务! 我是pool-1-thread-5线程,正在执行14的任务! 我是pool-1-thread-8线程,正在执行15的任务!通过上面这个方法,我们可以看出,如果任务数量正好是15(for循环次数)个,则线程池中可以创建的总线程数量为10个(new ThreadPoolExecutor的第二个参数), 加上5个阻塞队列(new ArrayBlockingQueue<>(5)),这个线程池只可以同时执行10个任务,然后还有5个任务在阻塞队列中! 而在这个例子里,我们创建了16个任务(for循环次数),在任务中,使用了sleep来延长任务存在的时间,则16个任务,超过了,10个线程加5个阻塞队列的容量,于是抛出了异常(拒绝策略使用的是默认的)! 如果切换最后一个参数(new ThreadPoolExecutor.AbortPolicy()),换掉拒绝策略,会有什么区别呢??请参考下方,自行尝试!
分类:除了上述这种示例,一下4中也是比较常用的!
创建无大小限制的线程池(newCachedThreadPool())创建固定大小的线程池(newFixedThreadPool(int nThreads))单线程池 (newSingleThreadScheduledExecutor())创建定时调度池 (newScheduledThreadPool(int corePoolSize)