1.概述
线程池(Thread Pool)是一种多线程处理形式,它允许一个或多个线程并行执行,以减少在创建和销毁线程上花费的时间以及系统资源的开销。线程池不仅提高了程序的响应速度,还增强了系统的吞吐量。
线程池主要由一个或多个创建好的线程和一个线程安全的任务队列组成。当需要执行新任务时,线程池会尝试从任务队列中获取任务,并由一个或多个空闲的线程来执行这些任务。如果所有线程都在忙,那么新任务就会在队列中等待,直到有线程空闲出来。
线程池中的线程数量可以根据需要进行调整,以适应不同的工作负载。线程池还提供了对并发执行的任务数量的控制,以及提供了一种机制来管理在应用程序中创建和销毁线程的过程。
2.线程池的实现的两种方式
Java中的java.util.concurrent.ExecutorService接口及其实现类(如ThreadPoolExecutor)提供了线程池的实现。
2.1.实例化ThreadPoolExecutor类:
这种方式需要更多的配置和了解底层细节,因为你需要直接设置线程池的核心大小、最大大小、队列容量、拒绝策略等参数。例如:
ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, // 核心线程数
maximumPoolSize, // 最大线程数
keepAliveTime, // 临时线程存活时间
TimeUnit.MILLISECONDS, // 临时线程存活的时间单位
workQueue, // 代表用于存放待执行任务的队列
threadFactory,// 线程工厂
handler // 拒绝策略 );
线程池使用图解
ExcutorService提供的线程池执行方法
线程池执行Runnable任务
package pool;
public class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package pool;
import com.sun.jmx.remote.internal.ArrayQueue;
import java.sql.Time;
import java.util.concurrent.*;
public class Main {
public static void main(String[] args) {
//创建线程池
ExecutorService pool = new ThreadPoolExecutor(3,
5,
8,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(3),
Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
//线程池创建一个新的任务执行Runnable任务
Runnable runnable=new MyRunnable();
pool.execute(runnable);
pool.execute(runnable);
pool.execute(runnable);
pool.execute(runnable);
pool.execute(runnable);
pool.execute(runnable);
pool.execute(runnable);
pool.execute(runnable);
// pool.execute(runnable);
}
}
执行结果
拒绝策略
当再多添加一个任务,线程池就会拒绝分配线程,下面是默认的拒绝策略AbortPolicy
其他拒绝策略:
- AbortPolicy(默认策略):
直接抛出RejectedExecutionException异常,阻止任务提交。 - CallerRunsPolicy:
不抛出异常,也不丢弃任务,而是由调用者所在的线程来运行这个任务。这意味着提交任务的线程会负责执行该任务。 - DiscardPolicy:
静默地丢弃无法处理的任务,不抛出任何异常。 - DiscardOldestPolicy:
静默地丢弃队列中最旧的任务,然后尝试重新提交新任务。
线程池执行Callable任务
package pool;
import java.util.concurrent.Callable;
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return Thread.currentThread().getName();
}
}
package pool;
import com.sun.jmx.remote.internal.ArrayQueue;
import java.sql.Time;
import java.util.concurrent.*;
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建线程池
ExecutorService pool = new ThreadPoolExecutor(3,
5,
8,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(3),
Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
//线程池创建新的任务执行Callable
Callable<String> callable=new MyCallable();
Future<String> submit1 = pool.submit(callable);
Future<String> submit2 = pool.submit(callable);
Future<String> submit3 = pool.submit(callable);
Future<String> submit4 = pool.submit(callable);
Future<String> submit5 = pool.submit(callable);
Future<String> submit6 = pool.submit(callable);
Future<String> submit7 = pool.submit(callable);
Future<String> submit8 = pool.submit(callable);
System.out.println(submit1.get());
System.out.println(submit2.get());
System.out.println(submit3.get());
System.out.println(submit4.get());
System.out.println(submit5.get());
System.out.println(submit6.get());
System.out.println(submit7.get());
System.out.println(submit8.get());
}
}
执行结果
2.2.通过Executors工厂类创建线程池
主要方法:
-
- Executors.newFixedThreadPool(int nThreads):创建一个可重用固定线程数的线程池。如果所有线程都在工作,新提交的任务会等待,直到有线程空闲出来。
- Executors.newSingleThreadExecutor():创建一个单线程的线程池。这意味着无论提交多少任务,它们都将按顺序执行。
- Executors.newCachedThreadPool():创建一个可根据需要创建新线程的线程池,但在以前构造的线程可用时将重用它们。