使用ExecutorService线程池技术的几点思路及作用
一、Java单线程与ExecutorService线程池的对比
在Java线程的构造中,Runnable并不代表线程,只是创建了一个接口,为线程提供方便。Thread才是真正的线程,实现了相关的功能。
在我们的Spring Boot项目中,Spring Boot项目启动就是代表一个主线程,如果在启动过程中报错,则主线程会中断,程序无法运行。如果Spring Boot启动成功之后,新开启的子线程启动报错异常,不会影响主线程运行
。
1.1Thread的弊端
(1)少了定时、定期、并发控制的逻辑;
(2)新建对象的性能存在问题;
(3)可能不断创建线程,会造成Java程序内存溢出、内存泄漏。
1.2线程池的优点
(1) 能够提供连接池管理线程,避免进度开销,占用开销;
(2)能够提供任务队列管理,当任务队列占用满时,可以拒绝后来的线程;
(3)可以通过队列的形式,逐步取出空闲线程进行任务调度;
(4)当队列中的线程异常时,可以重新创建别的线程进行处理;
(5)能够缓存线程,避免性能影响,对线程池进行管理。
二、线程池的几种用法
2.1newCachedThreadPool
通过无参数,创建无界缓存队列。可以回收超过60秒的空闲线程。当任务超过线程池中的线程数可以创建新线程,线程池的上限可以无限放大,是一种比较常用的线程池管理方法:
示例如下:
ExecutorService testCachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int undo = i;
testCachedThreadPool .execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+",undo="+undo);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
运行效果:
newpool-i-thread-i, undo=0
newpool-i-thread-i,undo=1
newpool-i-thread-i,undo=2
newpool-i-thread-i,undo=3
newpool-i-thread-i,undo=4
newpool-i-thread-i,undo=5
newpool-i-thread-i,undo=6
newpool-i-thread-i,undo=7
newpool-i-thread-i,undo=8
2.2newFixedThreadPool
通过创建固定大小的线程池,将超过线程池大小的线程加入LinkedBlockingQueue队列wait加入:
ExecutorService testFixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int undo= i;
testFixedThreadPool .execute(new Runnable() {
@Override
public void run() {
log.info(Thread.currentThread().getName()+",undo="+undo);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
运行效果:
newpool-i-thread-1, undo=0
newpool-i-thread-2,undo=1
newpool-i-thread-3,undo=2
newpool-i-thread-1,undo=3
newpool-i-thread-2,undo=4
newpool-i-thread-3,undo=5
newpool-i-thread-1,undo=6
newpool-i-thread-2,undo=7
newpool-i-thread-3,undo=8
2.3newSingleThreadExecutor
通过创建仅有单个线程的线程池,不需要加入参数,通过唯一的单线程来管理队列,其他的线程都保存在LinkedBlockingQueue中。能过控制线程串行执行:
ExecutorService testSingleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
final int undo = i;
testSingleThreadExecutor.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+",undo="+undo);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
运行效果,所有任务都等待线程一进行:
newpool-i-thread-1, undo=0
newpool-i-thread-1,undo=1
newpool-i-thread-1,undo=2
newpool-i-thread-1,undo=3
newpool-i-thread-1,undo=4
2.4newScheduledThreadPool
可创建一个定时执行或周期执行任务的线程池,可以指定线程池核心线程个数
ScheduledExecutorService testScheduledThreadPool = Executors.newScheduledThreadPool(5);
//延迟二秒执行定时线程数
testScheduledThreadPool .schedule(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+", delay 2s");
}
}, 2, TimeUnit.SECONDS);
//通过周期性地执行任务,延迟5秒后,每3s周期性执行任务
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+", every 5s");
}
}, 5, 3, TimeUnit.SECONDS);
运行效果:
newpool-i-thread-1, delay 2s
newpool-i-thread-1,every 5s
newpool-i-thread-2,every 5s
newpool-i-thread-2,every 5s
newpool-i-thread-3,every 5s
newpool-i-thread-4,every 5s
可以通过延迟执行,为我们创建定时任务调度。
三、线程池应用场景
对比单线程处理,线程池技术节约了资源,便于常态化管理多线程运行。对于提升大家的职业素养是非常有好处的。
本文暂时没有评论,来添加一个吧(●'◡'●)