异步编程学习之路(五)-线程池原理及使用,2024年最新springcloudalibb面试题
先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
正文
也就是说在((当前工作线程数 > 最大线程数) || (当前队列不为空 && (允许核心线程超时 || 当前工作线程数 > 核心线程)) && (当前工作线程数 > 1 || 队列为空) 的时候GC会将线程回收。
5、unit(存活时间单位)
参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小时
TimeUnit.MINUTES; //分钟
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //纳秒
6、workQueue(任务阻塞队列)
workQueue是用来存储等待执行的任务,一般有三种选择(ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue),他们的初始化参数如下:
/**
-
Creates an {@code ArrayBlockingQueue} with the given (fixed)
-
capacity and default access policy.
-
@param capacity the capacity of this queue
-
@throws IllegalArgumentException if {@code capacity < 1}
*/
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
/**
-
Creates an {@code ArrayBlockingQueue} with the given (fixed)
-
capacity and the specified access policy.
-
@param capacity the capacity of this queue
-
@param fair if {@code true} then queue accesses for threads blocked
-
on insertion or removal, are processed in FIFO order;
-
if {@code false} the access order is unspecified.
-
@throws IllegalArgumentException if {@code capacity < 1}
*/
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
/**
-
Creates an {@code ArrayBlockingQueue} with the given (fixed)
-
capacity, the specified access policy and initially containing the
-
elements of the given collection,
-
added in traversal order of the collection’s iterator.
-
@param capacity the capacity of this queue
-
@param fair if {@code true} then queue accesses for threads blocked
-
on insertion or removal, are processed in FIFO order;
-
if {@code false} the access order is unspecified.
-
@param c the collection of elements to initially contain
-
@throws IllegalArgumentException if {@code capacity} is less than
-
{@code c.size()}, or less than 1.
-
@throws NullPointerException if the specified collection or any
-
of its elements are null
*/
public ArrayBlockingQueue(int capacity, boolean fair,
Collection<? extends E> c) {
this(capacity, fair);
final ReentrantLock lock = this.lock;
lock.lock(); // Lock only for visibility, not mutual exclusion
try {
int i = 0;
try {
for (E e : c) {
checkNotNull(e);
items[i++] = e;
}
} catch (ArrayIndexOutOfBoundsException ex) {
throw new IllegalArgumentException();
}
count = i;
putIndex = (i == capacity) ? 0 : i;
} finally {
lock.unlock();
}
}
ArrayBlockingQueue数据结构是数组,存在三种构造方式,我们通常用第一种构造方式,参数含义分别是:
1、capacity:数组长度。
2、fair:默认false,如果设置为true则插入或删除时阻塞的线程的队列访问按FIFO顺序处理,如果设置为false则访问顺序未知。
3、c:最初要包含的元素的集合,下面的items是Object数组。
/**
-
Creates a {@code LinkedBlockingQueue} with the given (fixed) capacity.
-
@param capacity the capacity of this queue
-
@throws IllegalArgumentException if {@code capacity} is not greater
-
than zero
*/
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node(null);
}
LinkedBlockingQueue数据结构是链表,只有一种构造方式,参数是链表长度。
/**
- Creates a {@code SynchronousQueue} with nonfair access policy.
*/
public SynchronousQueue() {
this(false);
}
/**
-
Creates a {@code SynchronousQueue} with the specified fairness policy.
-
@param fair if true, waiting threads contend in FIFO order for
-
access; otherwise the order is unspecified.
*/
public SynchronousQueue(boolean fair) {
transferer = fair ? new TransferQueue() : new TransferStack();
}
SynchronousQueue存在两种构造方式,参数含义:
fair:默认false,如果设置为true则插入或删除时阻塞的线程的队列访问按FIFO顺序处理,如果设置为false则访问顺序未知。
ArrayBlockingQueue和PriorityBlockingQueue使用较少,一般使用LinkedBlockingQueue和Synchronous。线程池的排队策略与BlockingQueue有关。
7、threadFactory(用来创建线程的工厂)
ThreadFactory很简单,就是一个线程工厂也就是负责生产线程的,代码如下:
public interface ThreadFactory {
/**
-
Constructs a new {@code Thread}. Implementations may also initialize
-
priority, name, daemon status, {@code ThreadGroup}, etc.
-
@param r a runnable to be executed by new thread instance
-
@return constructed thread, or {@code null} if the request to
-
create a thread is rejected
*/
Thread newThread(Runnable r);
}
其中newThread方法就是用来生产线程的,子类需要实现这个方法来根据自己规则生产相应的线程。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
如果ThreadPoolExecutor在构造时没有传入threadFactory则默认使用Executors.defaultThreadFactory()来作为线程工厂。
8、handler(任务拒绝策略)
任务拒绝策略常用的有四种,最上层接口代码如下:
/**
-
A handler for tasks that cannot be executed by a {@link ThreadPoolExecutor}.
-
@since 1.5
-
@author Doug Lea
*/
public interface RejectedExecutionHandler {
/**
-
Method that may be invoked by a {@link ThreadPoolExecutor} when
-
{@link ThreadPoolExecutor#execute execute} cannot accept a
-
task. This may occur when no more threads or queue slots are
-
available because their bounds would be exceeded, or upon
-
shutdown of the Executor.
-
In the absence of other alternatives, the method may throw
-
an unchecked {@link RejectedExecutionException}, which will be
-
propagated to the caller of {@code execute}.
-
@param r the runnable task requested to be executed
-
@param executor the executor attempting to execute this task
-
@throws RejectedExecutionException if there is no remedy
*/
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
Java中的实现类有四种:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
开发人员可以在初始化线程池的时候根据业务需求灵活配置不同的拒绝策略。
上文中说不建议直接使用Executors,因为Executors在四个方法中(newCachedThreadPool、newFixedThreadPool、newScheduledThreadPool、newSingleThreadExecutor)阻塞队列默认大小是Integer.MAX_VALUE(无限大),这样造成的问题就是超过核心线程数的线程会不断放入阻塞队列中(前提是核心最大线程数设置的不合理),为了规避这个风险强烈建议在初始化ThreadPoolExcetor时自定义阻塞队列的大小。
二、Executors线程池
Executors中常用的线程池有四种,下面将通过实例讲解使用方法,代码如下:
1、 FixedThreadPool
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolTest {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(3);
for(int i = 1; i < 5; i++) {
final int taskID = i;
threadPool.execute(new Runnable() {
public void run() {
for(int i = 1; i < 5; i++) {
try {
Thread.sleep(20);// 为了测试出效果,让每次任务执行都需要一定时间
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(“第” + taskID + “次任务的第” + i + “次执行”);
}
}
});
}
threadPool.shutdown();// 任务执行完毕,关闭线程池
}
}
运行结果:
第1次任务的第1次执行
第2次任务的第1次执行
第3次任务的第1次执行
第2次任务的第2次执行
第3次任务的第2次执行
第1次任务的第2次执行
第3次任务的第3次执行
第1次任务的第3次执行
第2次任务的第3次执行
第3次任务的第4次执行
第2次任务的第4次执行
第1次任务的第4次执行
第4次任务的第1次执行
第4次任务的第2次执行
第4次任务的第3次执行
第4次任务的第4次执行
上段代码中,创建了一个固定大小的线程池,容量为3,然后循环执行了4个任务,由输出结果可以看到,前3个任务首先执行完,然后空闲下来的线程去执行第4个任务,在FixedThreadPool中,有一个固定大小的池,如果当前需要执行的任务超过了池大小,那么多于的任务等待状态,直到有空闲下来的线程执行任务,而当执行的任务小于池大小,空闲的线程也不会去销毁。
2、 CachedThreadPool
上段代码其它地方不变,将newFixedThreadPool方法换成newCachedThreadPool方法。
运行结果:
第3次任务的第1次执行
第4次任务的第1次执行
第1次任务的第1次执行
第2次任务的第1次执行
第4次任务的第2次执行
第3次任务的第2次执行
第2次任务的第2次执行
第1次任务的第2次执行
第2次任务的第3次执行
第3次任务的第3次执行
第1次任务的第3次执行
第4次任务的第3次执行
第2次任务的第4次执行
第4次任务的第4次执行
第3次任务的第4次执行
第1次任务的第4次执行
可见,4个任务是交替执行的,CachedThreadPool会创建一个缓存区,将初始化的线程缓存起来,如果线程有可用的,就使用之前创建好的线程,如果没有可用的,就新创建线程,终止并且从缓存中移除已有60秒未被使用的线程。
3、 SingleThreadExecutor
上段代码其它地方不变,将newFixedThreadPool方法换成newSingleThreadExecutor方法。
运行结果:
第1次任务的第1次执行
第1次任务的第2次执行
第1次任务的第3次执行
第1次任务的第4次执行
第2次任务的第1次执行
第2次任务的第2次执行
第2次任务的第3次执行
第2次任务的第4次执行
第3次任务的第1次执行
第3次任务的第2次执行
第3次任务的第3次执行
第3次任务的第4次执行
第4次任务的第1次执行
第4次任务的第2次执行
第4次任务的第3次执行
第4次任务的第4次执行
四个任务是顺序执行的,SingleThreadExecutor得到的是一个单个的线程,这个线程会保证你的任务执行完成,如果当前线程意外终止,会创建一个新线程继续执行任务,这和我们直接创建线程不同,也和newFixedThreadPool(1)不同。
4、ScheduledThreadPool
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolTest {
public static void main(String[] args) {
ScheduledExecutorService schedulePool = Executors.newScheduledThreadPool(1);
// 5秒后执行任务
最后
看完上述知识点如果你深感Java基础不够扎实,或者刷题刷的不够、知识不全面
小编专门为你量身定制了一套<Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法>
针对知识面不够,也莫慌!还有一整套的<Java核心进阶手册>,可以瞬间查漏补缺
全都是一丢一丢的收集整理纯手打出来的
更有纯手绘的各大知识体系大纲,可供梳理:Java筑基、MySQL、Redis、并发编程、Spring、分布式高性能架构知识、微服务架构知识、开源框架知识点等等的xmind手绘图~
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
最后
看完上述知识点如果你深感Java基础不够扎实,或者刷题刷的不够、知识不全面
小编专门为你量身定制了一套<Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法>
[外链图片转存中…(img-X7CtOhHc-1713468644856)]
针对知识面不够,也莫慌!还有一整套的<Java核心进阶手册>,可以瞬间查漏补缺
[外链图片转存中…(img-kahPyZPu-1713468644856)]
全都是一丢一丢的收集整理纯手打出来的
更有纯手绘的各大知识体系大纲,可供梳理:Java筑基、MySQL、Redis、并发编程、Spring、分布式高性能架构知识、微服务架构知识、开源框架知识点等等的xmind手绘图~
[外链图片转存中…(img-2dMI4tuN-1713468644857)]
[外链图片转存中…(img-2kqYdnG7-1713468644857)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-KB0tnTvt-1713468644858)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!