一)线程池简介
1、减少线程的频繁创建、销毁。
2、可有效的使用和管理线程,提升资源重复使用率,避免资源不足引起的一些问题。
二)newFixedThreadPool
原理:创建一个固定数量大小的线程池,当线程任务数超过固定大小时,未执行的线程任务进行阻塞队列,等待线程池调度。
示例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FixedDemo {
public static void main(String[] args) {
// 创建一个固定数量的线程池
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
final int idx = i;
executor.execute(new Runnable() { // 创建线程并添加到线程池中, 并启动运行线程
@Override
public void run() {
System.out.println("当前线程名称:" + Thread.currentThread().getName() + ", 参数idx = " + idx);
}
});
}
executor.shutdown(); // 关闭线程池
}
}
执行效果图:
说明:创建一个固定数量为5的线程池,并创建10个线程任务添加到线程池中,线程池调度器会分配线程来处理任务。
源码:Executors类中newFixedThreadPool()方法。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
缺点:该方式创建线程池时,会使用LinkedBlockingQueue无界队列默认构造方法,该默认构造方法大小为Integer.MAX_VALUE,所以当线程任务超多时,可能会堆积大量的请求,从而导致 OOM。但一般的系统直接使用该方式即可。
解决方式:直接用new ThreadPoolExecutor的方式创建线程池,指定具体的参数信息。
三)newSingleThreadExecutor
原理:创建一个单例线程池, 只存在一个线程运行, 多的线程任务进行阻塞状态。
示例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SingleDemo {
public static void main(String[] args) {
// 创建一个单例线程池, 只存在一个线程运行, 多的线程任务进行阻塞状态
ExecutorService executor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int idx = i;
executor.execute(new Runnable() { // 创建线程并添加到线程池中, 并启动运行线程
@Override
public void run() {
System.out.println("当前线程名称:" + Thread.currentThread().getName() + ", 参数idx = " + idx);
}
});
}
executor.shutdown(); // 关闭线程池
}
}
执行效果图:
说明:创建一个单例线程池,并创建10个线程任务添加到线程池中,线程任务被一个一个的顺序执行。
源码:Executors类中newSingleThreadExecutor()方法。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
缺点:同newFixedThreadPool()方法一样。
四)newCachedThreadPool
原理:创建一个缓存线程池,当线程数过大,可回收多余线程,如线程数不足,创建新线程。
示例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CachedDemo {
public static void main(String[] args) {
// 创建一个缓存线程池, 当线程数过大,可回收多余线程, 如线程数不足, 创建新线程
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int idx = i;
executor.execute(new Runnable() { // 创建线程并添加到线程池中, 并启动运行线程
@Override
public void run() {
System.out.println("当前线程名称:" + Thread.currentThread().getName() + ", 参数idx = " + idx);
}
});
}
executor.shutdown(); // 关闭线程池
}
}
执行效果图:
说明:创建一个缓存线程池,并创建10个线程任务添加到线程池中,由于线程运行速度快,会不断创建新线程来执行任务。
源码:Executors类中newCachedThreadPool()方法。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
缺点:该方式创建线程时,线程的核心数量大小为0,线程最大数量为Integer.MAX_VALUE,此方式允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
解决方式:直接用new ThreadPoolExecutor的方式创建线程池,指定具体的参数信息。
五)newScheduledThreadPool
原理:创建一个定时调度线程池,内置一个延迟队列,可按照设定的固定时间周期性的执行任务。
示例:
import java.text.DateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledDemo {
public static void main(String[] args) {
// 创建一个定时调度线程池, 内置一个延迟队列, 可按照设定的固定时间周期性的执行任务
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
executor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
long start = System.currentTimeMillis();
System.out.println("当前线程名: " + Thread.currentThread().getName()
+ ", scheduleAtFixedRate开始执行时间: " + DateFormat.getTimeInstance().format(new Date()));
try {
Thread.sleep(5000); // 睡眠5秒钟, 方便测试
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("当前线程名: " + Thread.currentThread().getName()
+ ", scheduleAtFixedRate执行花费时间: " + (end - start) / 1000 + "s");
System.out.println("当前线程名: " + Thread.currentThread().getName()
+ ", scheduleAtFixedRate执行完成时间: " + DateFormat.getTimeInstance().format(new Date()));
System.out.println("----------------------分割线-----------------------");
}
}, 1, 5, TimeUnit.SECONDS);
}
}
执行效果图:
说明:创建一个定时调度线程池,添加一个定时调度任务,每隔5秒中执行一遍。
ScheduledFuture<?> scheduleWithFixedDelay
(Runnable command, // 要执行的任务
long initialDelay, // 延迟第一次执行的时间
long delay, // 一个执行终止与下一个执行的开始之间的延迟
TimeUnit unit); //initialDelay和delay参数的时间单位
// 一个ScheduledFuture代表待完成的任务,其 get()方法将在取消时抛出异常
缺点:同newCachedThreadPool()方法一样。
识别二维码关注个人微信公众号
本章完结,待续,欢迎转载!
本文说明:该文章属于原创,如需转载,请标明文章转载来源!