Java线程的四种创建方式:
1 使用Thread子类创建和启动线程
2 使用实现Runnable的实现类创建和启动线程
3 使用Callable和FutureTask来创建异步任务,然后创建线程实例
4 通过线程池创建线程(JUC)
(1)向线程池提交任务的两种方式:
方式一:使用execute方法(无返回值)
void execute(Runnable command);
方式二:使用submit方法(有返回值、可简单管理线程,并且可以处理异常)
Future<?> submit(Runnable task);
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;
(2)关闭线程池:
pool.shutdown();
4.1 Executors四个快捷创建线程池方法(不推荐)
4.1.1 newSingleThreadExecutor()创建单一线程池
(1)任务按照次序执行
(2)池中只有唯一线程,并且存活时间是无限的
(3)线程繁忙时,新任务会进入到阻塞队列
场景:任务依次执行。
4.1.2 newFixedThreadPool(3)创建固定数量线程池
场景:处理CPU密集型的任务。在CPU被工作线程长时间使用的情况下,能确保尽可能少的分配线程。
弊端:内部使用*队列来存放任务,当任务超过线程池最大容量需要处理时,队列无限增大,使服务器资源耗尽。
4.1.3 newCachedThreadPool()可缓存线程池
场景:快速处理突发性强、耗时较短的任务。
弊端:没有最大线程池数量限制。
4.1.4 newScheduledThreadPool(2)可调度线程池
// 内含一个线程池
newSingleThreadScheduledThreadPool();
// 内含n个线程池
newScheduledThreadPool(int corePoolSize);
通过scheduleAtFixedRate方法提交任务:
ScheduledFuture<?> scheduleAtFixedRate(
Runnable command,
// 首次执行任务延迟时间
long initialDelay,
// 执行任务间隔时间
long period,
// 计时单位
TimeUnit unit);
场景:周期性执行任务场景。
4.2 创建标准线程池的方法(推荐)
快捷创建线程池的方法存在严重的性能问题,所以大部分企业都禁止使用快捷线程池,要求通过标准构造器ThreadPoolExecutor构造线程池。
// 标准构造器
public ThreadPoolExecutor(
// 核心线程数,即使线程空闲(idle),也不会回收
int corePoolSize,
// 线程数上限
int maximumPoolSize,
// 线程最大空闲(idle)时长
long keepAliveTime, TimeUnit unit,
// 任务的排队队列
BlockingQueue<Runnable> workQueue,
// 新线程的产生方式
ThreadFactory threadFactory,
// 拒绝策略
RejectedExecutionHandler handler)