文章目录
1.为什么使用线程池
使用多线程的开发中,频繁创建和销毁线程会带来较大的开销。我们可以使用线程池来有效的管理线程,它是一组预先创建的线程,可以重复使用,提高了线程的利用率,并且能够更好地控制线程的数量和执行方式。
2.线程池有哪些种类
1) 核心接口
线程池的主要接口是 Executor
和 ExecutorService
-
Executor
接口: 是线程池的根接口,只有一个execute
方法用于执行任务public interface Executor { void execute(Runnable var1); }
-
ExecutorService
接口: 继承自Executor
,扩展了一些功能,如任务提交、任务执行、任务取消等public interface ExecutorService extends Executor { void shutdown() List<Runnable> shutdownNow() boolean isShutdown() boolean isTerminated() boolean awaitTermination() <T> Future<T> submit() Future<?> submit() <T> List<Future<T>> invokeAll() <T> T invokeAny() }
2)线程池分类
FixedThreadPool
固定大小的线程池,每个任务都被分配一个线程
示例代码:
public class Demo {
public static void main(String[] args) {
// 创建固定大小(3个)的线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
// 提交5个任务
for (int i = 0; i < 5; i++) {
executor.execute(new RunnableDemo());
}
// 关闭线程池
executor.shutdown();
}
}
class RunnableDemo implements Runnable {
@Override
public void run() {
String tName = Thread.currentThread().getName();
System.out.println(tName + "正在执行...");
}
}
输出结果:
pool-1-thread-1正在执行…
pool-1-thread-3正在执行…
pool-1-thread-3正在执行…
pool-1-thread-2正在执行…
pool-1-thread-1正在执行…
在这个例子中,创建了一个固定大小为3的线程池,提交了5个任务。线程池会根据任务数量和线程池大小来调度执行任务。通过 execute()
方法提交任务,线程池会自动选择线程执行任务。最后,调用 shutdown()
方法关闭线程池。
CachedThreadPool
可根据需要创建新线程的线程池,适用于执行很多短期异步任务的小程序
示例代码:
public class Demo {
public static void main(String[] args) {
// 创建 CachedThreadPool
ExecutorService executor = Executors.newCachedThreadPool();
// 提交任务
for (int i = 0; i < 5; i++) {
executor.execute(new RunnableDemo());
}
// 关闭线程池
executor.shutdown();
}
}
class RunnableDemo implements Runnable {
@Override
public void run() {
String tName = Thread.currentThread().getName();
System.out.println(tName + "正在执行...");
}
}
输出结果:
pool-1-thread-1正在执行…
pool-1-thread-3正在执行…
pool-1-thread-2正在执行…
pool-1-thread-5正在执行…
pool-1-thread-4正在执行…
在这个例子中,Executors.newCachedThreadPool()
创建了一个 CachedThreadPool
,并提交了5个任务给线程池执行。由于 CachedThreadPool
的特性,线程池会根据需要动态创建新线程,并在一段时间内保留空闲线程以备复用。在这个例子中,任务数量较少,因此线程池可能会重用现有线程,也可能会创建新线程。最后,调用 shutdown()
方法关闭线程池。
SingleThreadExecutor
单线程的线程池,保证所有任务按照指定顺序(FIFO,LIFO,优先级)执行
示例代码:
public class Demo {
public static void main(String[] args) {
// 创建 SingleThreadExecutor
ExecutorService executor = Executors.newSingleThreadExecutor();
// 提交任务
for (int i = 0; i < 5; i++) {
executor.execute(new RunnableDemo());
}
// 关闭线程池
executor.shutdown();
}
}
class RunnableDemo implements Runnable {
@Override
public void run() {
String tName = Thread.currentThread().getName();
System.out.println(tName + "正在执行...");
}
}
输出结果:
pool-1-thread-1正在执行…
pool-1-thread-1正在执行…
pool-1-thread-1正在执行…
pool-1-thread-1正在执行…
pool-1-thread-1正在执行…
在这个例子中,Executors.newSingleThreadExecutor()
创建了一个 SingleThreadExecutor
,并提交了5个任务给线程池执行。由于 SingleThreadExecutor
的特性,所有任务会按照提交的顺序在同一个线程中执行。即使有多个任务并发提交,线程池也会保证这些任务一个接一个地执行。最后调用 shutdown()
方法关闭线程池。
ScheduledThreadPool
定时任务线程池,用于定时执行任务
示例代码:
public class Demo {
public static void main(String[] args) {
// 创建 ScheduledThreadPool
ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(3);
// 延迟任务
scheduledExecutor.schedule(new RunnableDemo(), 2, TimeUnit.SECONDS);
// 周期性任务,每隔一秒执行一次
scheduledExecutor.scheduleAtFixedRate(new RunnableDemo(), 0, 1, TimeUnit.SECONDS);
// 周期性任务,任务执行完成后延迟一秒再执行下一次
scheduledExecutor.scheduleWithFixedDelay(new RunnableDemo(), 0, 1, TimeUnit.SECONDS);
// 主线程等待一段时间,观察任务的执行
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 关闭线程池
scheduledExecutor.shutdown();
}
}
class RunnableDemo implements Runnable {
@Override
public void run() {
String tName = Thread.currentThread().getName();
System.out.println(tName + "正在执行...");
}
}
输出结果:
pool-1-thread-1正在执行…
pool-1-thread-3正在执行…
pool-1-thread-1正在执行…
pool-1-thread-2正在执行…
pool-1-thread-3正在执行…
pool-1-thread-3正在执行…
pool-1-thread-3正在执行…
pool-1-thread-3正在执行…
pool-1-thread-3正在执行…
pool-1-thread-2正在执行…
pool-1-thread-1正在执行…
pool-1-thread-3正在执行…
pool-1-thread-3正在执行…
pool-1-thread-1正在执行…
pool-1-thread-2正在执行…
pool-1-thread-3正在执行…
pool-1-thread-1正在执行…
pool-1-thread-2正在执行…
pool-1-thread-3正在执行…
pool-1-thread-1正在执行…
pool-1-thread-2正在执行…
在这个例子中,Executors.newScheduledThreadPool(3)
创建了一个大小为3的 ScheduledThreadPool
。通过 schedule
方法可以延迟执行任务,通过 scheduleAtFixedRate
和 scheduleWithFixedDelay
方法可以执行周期性任务。最后通过 shutdown
方法关闭线程池。在主线程等待一段时间后,可以观察到任务的执行情况。
总结
使用线程池是编写高效多线程程序的一种重要方式。它能够降低线程创建和销毁的开销,更好地管理线程的数量,提高系统的性能和响应速度。在选择线程池时,需要根据具体的需求和场景选择合适的线程池类型。