Java中基本线程池介绍
程序员文章站
2022-06-01 13:29:35
...
文章目录
前言
本文章只针对Exectors去创建线程池,让大家对线程池先有点基本的了解,但是实际开发中不允许用这样的方式去创建,而是通过ThreadPoolExecutor方式(最原始的线程池创建方式,之后的文章会涉及)。
一、newFixedThreadPool
- 定义:创建一个线程池,重用固定数量的线程,从共享*队列中运行,使用提供的ThreadFactory在需要时创建新线程。 在任何时候,最多nThreads个线程将处于主动处理任务。 如果所有线程处于活动状态时,提交其他任务,则它们将在等待队列中直到线程可用。 如果任何线程由于在关闭之前的执行期间发生故障而终止,则如果需要执行后续任务,则新线程将占用它。 池中的线程将存在,直到它明确地被shutdown 。
- 使用场景:适用于任务量已知,相对耗时的任务。
- 举例加分析(代码中)
public class testCreateThreadPool {
public static void main(String[] args) {
//创建固定大小为3的线程
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i <5 ; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行");
}
});
}
//shutdown三个线程,结束
executorService.shutdown();
/*
运行结果:
pool-1-thread-2执行
pool-1-thread-3执行
pool-1-thread-2执行
pool-1-thread-3执行
pool-1-thread-1执行
*/
/*
分析:一共只有三个线程,因此这5个任务是由这三个线程完成的
*/
}
}
二、newCachedThreadPool
- 定义:一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程。 这些池通常会提高执行许多短暂异步任务的程序的性能。 调用execute将重用以前构造的线程(如果可用)。 如果没有可用的线程,将创建一个新的线程并将其添加到该池中。 未使用六十秒的线程将被终止并从缓存中删除。 因此,长时间保持闲置的池将不会消耗任何资源。
- 使用场景:适合任务数比较密集,但每个任务执行时间较短的情况。
- 举例加分析(代码中)
public class testCreateThreadPool {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i <5 ; i++) {
//Thread.sleep(100);//注释掉是运行结果1,不注释掉是运行结果2
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行");
}
});
}
/*
运行结果1:
pool-1-thread-4执行
pool-1-thread-3执行
pool-1-thread-2执行
pool-1-thread-5执行
pool-1-thread-1执行
运行结果2:
pool-1-thread-1执行
pool-1-thread-1执行
pool-1-thread-1执行
pool-1-thread-1执行
pool-1-thread-1执行
*/
/*
分析:
运行结果1一共创建了5个线程,这是因为5个任务之间的间隔很短,
第二个任务要执行时,第一个任务未完成(该任务创建的线程当前不可用)
因此只能在创建第二个,以此类推
运行结果2一共创建了1个线程,这是因为每个任务之间间隔了200ms,
这个时间足够创建的线程完成任务,在下一个任务到来前处于可用状态
*/
}
}
三、newSingleThreadExector
- 定义:创建一个使用从*队列运行的单个工作线程的执行程序。(注意:如果这个单个线程由于在关闭之前的执行过程中发生故障而终止,则如果需要执行后续任务,则新的线程将占用它。)任务保证顺序执行,并且不超过一个任务将被**在任何给定的时间。
- 使用场景:希望多个任务排队执行。因为线程数固定为1,任务数多于1时,会放入*队列排队。任务执行完毕后,这唯一的线程也不会被释放。
- 举例加分析(代码中)
public class testCreateThreadPool {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i <5 ; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行");
}
});
}
executorService.shutdown();
/*
运行结果:
pool-1-thread-1执行
pool-1-thread-1执行
pool-1-thread-1执行
pool-1-thread-1执行
pool-1-thread-1执行
*/
/*
分析:
因为该线程是单线程执行器,因此只有一个线程执行所有任务
*/
}
}
四、newScheduledThreadPool
- 定义:创建一个线程池,可以调度命令在给定的延迟之后运行,或定期执行。
- 使用场景:任务需要周期性或者定时执行。
- 举例加分析(代码中)
public class testCreateThreadPool {
//线程安全的队列
static Queue<Integer> queue = new ConcurrentLinkedQueue<Integer>();
static {
for (int i = 1; i <=5 ; i++) {
queue.add(i);
}
}
public static void main(String[] args) throws InterruptedException {
//获取时间
SimpleDateFormat sdf=new SimpleDateFormat("hh:mm:ss");
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
for (int i = 0; i <5 ; i++) {
int curVal=queue.poll();
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
System.out.println("在"+sdf.format(new Date())+"时,线程执行了第"+curVal+"个任务");
}
},curVal,TimeUnit.SECONDS);
}
scheduledExecutorService.shutdown();
/*
运行结果:
在09:31:28时,线程执行了第1个任务
在09:31:29时,线程执行了第2个任务
在09:31:30时,线程执行了第3个任务
在09:31:31时,线程执行了第4个任务
在09:31:32时,线程执行了第5个任务
*/
/*
分析:
public ScheduledFuture<?> schedule(Runnable command,
long delay, TimeUnit unit);
本例中delay为1,2,3,4,5,unit为秒,即5个任务分别延迟1,2,3,4,5秒后执行
*/
}
上一篇: 苹果属于酸性还是碱性?
推荐阅读