java线程池使用
线程池:
优点:
(1) 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗;
(2) 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行;
(3) 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
Executors提供四种线程池
ExecutorService ex = Executors.newCachedThreadPool();
ExecutorService ex = Executors.newFixedThreadPool(poolSize)
使用线程池:
-
1、创建线程池
-
2、创建任务
-
3、执行任务
-
4、关闭线程池
ThreadPoolExecutor
在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了资源的开销。而线程池不允许使用Executors去创建,而要通过ThreadPoolExecutor方式,这一方面是由于jdk中Executor框架虽然提供了如newFixedThreadPool()、newSingleThreadExecutor()、newCachedThreadPool()等创建线程池的方法,但都有其局限性,不够灵活;另外由于前面几种方法内部也是通过ThreadPoolExecutor方式实现,使用ThreadPoolExecutor有助于大家明确线程池的运行规则,创建符合自己的业务场景需要的线程池,避免资源耗尽的风险
构造函数的定义:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) ;
- corePoolSize
线程池大小,决定着新提交的任务是新开线程去执行还是放到任务队列中,也是线程池的最最核心的参数。一般线程池开始时是没有线程的,只有当任务来了并且线程数量小于corePoolSize才会创建线程。 - maximumPoolSize
最大线程数,线程池能创建的最大线程数量。 - keepAliveTime
在线程数量超过corePoolSize后,多余空闲线程的最大存活时间。 - unit
keepAliveTime的时间单位 - workQueue
存放来不及处理的任务的队列,是一个BlockingQueue。 - threadFactory
生产线程的工厂类,可以定义线程名,优先级等。 - handler 拒绝策略,当任务来不及处理的时候,如何处理。
AbortPolicy
-- 当任务添加到线程池中被拒绝时,它将抛出 RejectedExecutionException 异常。2、
CallerRunsPolicy
-- 当任务添加到线程池中被拒绝时,会在线程池当前正在运行的Thread线程池中处理被拒绝的任务。3、
DiscardOldestPolicy
-- 当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最旧的未处理任务,然后将被拒绝的任务添加到等待队列中。4、
DiscardPolicy
-- 当任务添加到线程池中被拒绝时,线程池将丢弃被拒绝 的任务。pool = new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
2、无界的任务队列:有界任务队列可以使用LinkedBlockingQueue实现,如下所示
pool = new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
自定义拒绝策略
pool = new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(5),
Executors.defaultThreadFactory(), new RejectedExecutionHandler() {
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println(r.toString()+"执行了拒绝策略");
}
});
创建任务:
任务分为两种:一种是有返回值的( callable ),一种是没有返回值的( runnable ). Callable与 Future 两功能是Java在后续版本中为了适应多并法才加入的,Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其他线程执行的任务。
- 无返回值的任务就是一个实现了runnable接口的类.使用run方法.
- 有返回值的任务是一个实现了callable接口的类.使用call方法.
Callable和Runnable的区别如下:
- Callable定义的方法是call,而Runnable定义的方法是run。
- Callable的call方法可以有返回值,而Runnable的run方法不能有返回值。
- Callable的call方法可抛出异常,而Runnable的run方法不能抛出异常。
执行任务
通过java.util.concurrent.ExecutorService接口对象来执行任务,该对象有两个方法可以执行任务execute和submit。execute这种方式提交没有返回值,也就不能判断是否执行成功。submit这种方式它会返回一个Future对象,通过future的get方法来获取返回值,get方法会阻塞住直到任务完成。
execute与submit区别:
- 接收的参数不一样
- submit有返回值,而execute没有
- submit方便Exception处理
- execute是Executor接口中唯一定义的方法;submit是ExecutorService(该接口继承Executor)中定义的方法
使用线程池
(1)调用Runnablepool.execute(new Runnable() {
@Override
public void run() {
// 输出内容:MyThreadFactory_testThread_0
System.out.println(Thread.currentThread().getName());
}
});
Future<String> future = pool.submit(new Callable<String>() { @Override public String call() throws Exception { return Thread.currentThread().getName(); } });