1.通过Executors创建
Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。
下面这张图完整描述了线程池的类体系结构。
**Executor:**一个接口,其定义了一个接收Runnable对象的方法executor,其方法签名为executor(Runnable command),
**ExecutorService:**是一个比Executor使用更广泛的子类接口,其提供了生命周期管理的方法,以及可跟踪一个或多个异步任务执行状况返回Future的方法
**AbstractExecutorService:**ExecutorService执行方法的默认实现
ScheduledExecutorService:一个可定时调度任务的接口
ScheduledThreadPoolExecutor:ScheduledExecutorService的实现,一个可定时调度任务的线程池
**ThreadPoolExecutor:**线程池,可以通过调用Executors以下静态工厂方法来创建线程池并返回一个ExecutorService对象
(1)创建缓存线程池
Executors.newCacheThreadPool():可缓存线程池,先查看线程池中有没有之前创建的线程,如果有则直接使用。否则就新创建一个新的线程加入线程池中,我们经常用此类线程池来执行一些业务处理时间很短的任务。
源码
/**
* Creates a thread pool that creates new threads as needed, but
* will reuse previously constructed threads when they are
* available. These pools will typically improve the performance
* of programs that execute many short-lived asynchronous tasks.
* Calls to {@code execute} will reuse previously constructed
* threads if available. If no existing thread is available, a new
* thread will be created and added to the pool. Threads that have
* not been used for sixty seconds are terminated and removed from
* the cache. Thus, a pool that remains idle for long enough will
* not consume any resources. Note that pools with similar
* properties but different details (for example, timeout parameters)
* may be created using {@link ThreadPoolExecutor} constructors.
*
* @return the newly created thread pool
*/
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
/**
* Creates a thread pool that creates new threads as needed, but
* will reuse previously constructed threads when they are
* available, and uses the provided
* ThreadFactory to create new threads when needed.
* @param threadFactory the factory to use when creating new threads
* @return the newly created thread pool
* @throws NullPointerException if threadFactory is null
*/
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
通过源码可以看出是对ThreadPoolExecutor封装。阻塞队列不装线程,最大线程数是Integer最大值,可以不断创建线程。
注意线程太多会发生OOM。
代码实现
//缓存线程池
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i=0;i<10;i++) {
//模拟线程调用的时间间隔
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
cachedThreadPool.submit(()->{
//模拟业务处理时间
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("newCachedThreadPool创建线程池" + " " + Thread.currentThread().getName());
});
}
结果
newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-1
调大业务处理时间Thread.sleep(1000);,由于新创建的线程没有空闲,所以会一直创建新的线程,执行结果如下:
newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-2
newCachedThreadPool创建线程池 pool-1-thread-3
newCachedThreadPool创建线程池 pool-1-thread-4
newCachedThreadPool创建线程池 pool-1-thread-5
newCachedThreadPool创建线程池 pool-1-thread-6
newCachedThreadPool创建线程池 pool-1-thread-7
newCachedThreadPool创建线程池 pool-1-thread-8
newCachedThreadPool创建线程池 pool-1-thread-9
newCachedThreadPool创建线程池 pool-1-thread-10
(2)创建固定长度线程池
Executors.newFixedThreadPool():创建一个固定(指定)长度可重用的线程池,可以控制最大创建数,超过最大长度之后就会放入到队列进行等待。最大线程数=核心线程数。
源码
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
源码可以看出只是留了一个传线程数的口子,最大线程数=核心线程数。
代码实现
//固定线程池
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(2);
for (int i=0;i<10;i++) {
//模拟线程调用的时间间隔
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
newFixedThreadPool.submit(()->{
//模拟业务处理时间
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("newFixedThreadPool创建线程池" + " " + Thread.currentThread().getName());
});
}
结果
newFixedThreadPool创建线程池 pool-1-thread-1
newFixedThreadPool创建线程池 pool-1-thread-2
newFixedThreadPool创建线程池 pool-1-thread-1
newFixedThreadPool创建线程池 pool-1-thread-2
newFixedThreadPool创建线程池 pool-1-thread-1
newFixedThreadPool创建线程池 pool-1-thread-2
newFixedThreadPool创建线程池 pool-1-thread-1
newFixedThreadPool创建线程池 pool-1-thread-2
newFixedThreadPool创建线程池 pool-1-thread-1
newFixedThreadPool创建线程池 pool-1-thread-2
创建了两个线程的固定线程池,线程会进入等待队列,等有空闲线程再执行。使用LinkedBlockingQueue大小为Integer.MAX_VALUE。注意队列里放太多任务也会发生OOM的。
(3)定时执行的线程池
Executors.newScheduledThreadPool():创建一个支持定时或周期性的执行任务线程池,可以延时执行,可以用做执行定时任务的线程池。
源码
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
定时线程池是根据延时队列来实现的。
代码实现
//可定时执行的线程池
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yy-MM-dd hh:mm:ss");
ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(2);
//参数依次为:执行线程、初始化延时、线程调用时间间隔、计时单位
newScheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("newScheduledThreadPool创建线程池" + " " + Thread.currentThread().getName() + "执行时间" + simpleDateFormat.format(new Date()));
}
},5,10, TimeUnit.SECONDS);
结果
newScheduledThreadPool创建线程池 pool-1-thread-1执行时间22-07-19 11:02:04
newScheduledThreadPool创建线程池 pool-1-thread-1执行时间22-07-19 11:02:14
newScheduledThreadPool创建线程池 pool-1-thread-1执行时间22-07-19 11:02:24
newScheduledThreadPool创建线程池 pool-1-thread-1执行时间22-07-19 11:02:34
newScheduledThreadPool创建线程池 pool-1-thread-1执行时间22-07-19 11:02:44
newScheduledThreadPool创建线程池 pool-1-thread-1执行时间22-07-19 11:02:54
newScheduledThreadPool创建线程池 pool-1-thread-1执行时间22-07-19 11:03:04
第一个线程延时5s,线程间执行间隔10s。
scheduleAtFixedRate和scheduleWithFixedDelay区别
假设线程耗时1s,定时执行3s,则scheduleWithFixedDelay其实是4s,
scheduleAtFixedRate:固定周期运行。
scheduleWithFixedDelay:任务结束时间周期进行。
(4)单线程化线程池
Executors.newSingleThreadExecutor():创建一个单线程化线程池,它只能用一个工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
源码
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
最大线程数=核心线程数=1
代码实现
//单线程池
ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i=0;i<10;i++) {
//模拟线程调用的时间间隔
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
newSingleThreadExecutor.submit(()->{
//模拟业务处理时间
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("newSingleThreadExecutor创建线程池" + " " + Thread.currentThread().getName());
});
}
结果
newSingleThreadExecutor创建线程池 pool-1-thread-1
newSingleThreadExecutor创建线程池 pool-1-thread-1
newSingleThreadExecutor创建线程池 pool-1-thread-1
newSingleThreadExecutor创建线程池 pool-1-thread-1
newSingleThreadExecutor创建线程池 pool-1-thread-1
newSingleThreadExecutor创建线程池 pool-1-thread-1
newSingleThreadExecutor创建线程池 pool-1-thread-1
newSingleThreadExecutor创建线程池 pool-1-thread-1
newSingleThreadExecutor创建线程池 pool-1-thread-1
newSingleThreadExecutor创建线程池 pool-1-thread-1
执行代码会看到同一时间只有一个线程执行,其余的任务都会有序等待且有序的执行。
2.自己创建
执行代码
//ThreadFactory参数,可以通过实现自己手动写一个实现ThreadFactory的类作为参数放到这里
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60L,
TimeUnit.SECONDS, new LinkedBlockingDeque<>(1000), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r,"自定义线程池"+r.hashCode());
}
});
for (int i=0;i<10;i++) {
//模拟线程调用的时间间隔
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
threadPoolExecutor.submit(()->{
//模拟业务处理时间
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("newCachedThreadPool创建线程池" + " " + Thread.currentThread().getName());
});
}
}
结果
newCachedThreadPool创建线程池 自定义线程池445884362
newCachedThreadPool创建线程池 自定义线程池445884362
newCachedThreadPool创建线程池 自定义线程池445884362
newCachedThreadPool创建线程池 自定义线程池445884362
newCachedThreadPool创建线程池 自定义线程池445884362
newCachedThreadPool创建线程池 自定义线程池445884362
newCachedThreadPool创建线程池 自定义线程池445884362
newCachedThreadPool创建线程池 自定义线程池445884362
newCachedThreadPool创建线程池 自定义线程池445884362
newCachedThreadPool创建线程池 自定义线程池445884362
注意:以上线程池用完记得关闭。通过调用线程池的 shutdown 或 shutdownNow 方法来关闭线程池。
Executor和Executors区别
**Executor:**一个接口,其定义了一个接收Runnable对象的方法executor,其方法签名为executor(Runnable command)。
Executors:是对线程池的包装,前面讲到了前三种线程池的创建。