线程的创建方法
1、继承Thread类,没有返回值;
2、实现Runnable接口,没有返回值;
3、实现Callable接口通过FutureTask包装器来创建Thread线程,可以有返回值;
4、通过线程池实现,两种方法都提供。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
因为SynchronousQueue队列不保持它们,直接提交给线程,相当于队列大小为0,而最大线程数为Integer.MAX_VALUE,所以线程不足时,会一直创建新线程,等到线程空闲时,又有60秒存活时间,从而实现了一个可缓存的线程池。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
因为核心线程数与最大线程数相同,所以线程池的线程数是固定的,而且没有限制队列的大小,所以多余的任务均会被放到队列排队,从而实现一个固定大小,可控制并发数量的线程池。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());
}
因为使用了延迟队列,只有在延迟期满时才能从中提取到元素,从而实现定时执行的线程池。而周期性执行是配合上层封装的其他类来实现的,可以看ScheduledExecutorService类的scheduleAtFixedRate方法。
注意:这里用的是ScheduledExecutorService类的schedule()方法,不是ExecutorService类的execute()方法。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
因为核心线程数与最大线程数相同,均为1,所以线程池的线程数是固定的1个,而且没有限制队列的大小,所以多余的任务均会被放到队列排队,从而实现一个单线程按指定顺序执行的线程池。
/**
* @param corePoolSize 核心线程数,始终存活
* @param maximumPoolSize 线程池中允许的最大线程数
* @param keepAliveTime 存活时间,没有任务运行时存活的时间
* @param unit keepAliveTime的单位,
* TimeUnit枚举类,天、小时、分、秒、毫秒、微秒、纳秒
* @param workQueue 一个阻塞队列,用来存储等待执行的任务,均为线程安全,7种可选。
* 较常用的是LinkedBlockingQueue和Synchronous。
* 线程池的排队策略与BlockingQueue有关。 *
* @param threadFactory 线程工厂,主要用来创建线程,默及正常优先级、非守护线程。
* @param handler 拒绝策略,拒绝处理任务时的策略,4种可选,默认为AbortPolicy。
* @description ThreadPoolExecutor 线程池构造方法
*/
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
// 省略...
}
【强制】线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
Executors返回的线程池对象的弊端如下:
FixedThreadPool和SingleThreadPool:允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。
CachedThreadPool和ScheduledThreadPool:允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。
在线程池中,当核心线程数不够时,工作任务会存入线程队列中;
当线程队列存满时,才会去判断最大线程数是否已满,再创建新的线程;
如果队列存满,当前工作线程数等于最大线程数,则会根据选择的拒绝策略执行。