赞
踩
和j2ee的连接池技术很像,都属于池化技术。在手写多个线程的过程中,经常会new好几个thread对象,也就是为线程对象申请资源,然后在线程运行完相应的代码后再释放资源
这一过程只有两三个还好,而当高并发的情形下,很有可能有几百上千个线程需要频繁的创建、销毁。这就导致了非常严重的系统资源浪费。
于是线程池技术应运而生,有一个容器一开始就装了很多的线程,需要用的时候从容器中拿出来,不需要的时候再放回容器,这样就避免了频繁申请资源,销毁线程而导致的资源浪费,这个容器就是线程池
注意:线程池在创建之初默认是空的,默认能容纳int类型的最大值个线程
public class MyThreadPool { public static void main(String[] args) throws InterruptedException { /** * Executors 用于创建线程池对象 * ExecutorService 用于控制线程池 */ ExecutorService executorService = Executors.newCachedThreadPool(); executorService.submit(()->{ System.out.println(Thread.currentThread().getName() + " is running..."); }); Thread.sleep(2000); executorService.submit(()->{ System.out.println(Thread.currentThread().getName() + " is running..."); }); executorService.shutdown(); } }
一些说明:
1、当前版本会让Executors.newCachedThreadPool()报红
原因是使用Executors创建线程池不会传入这个参数而使用默认值所以我们常常忽略这一参数,而且默认使用的参数会导致资源浪费,不可取。
2、为什么运行结果是2个相同的线程
因为在线程池中一个线程使用完后会自动归还到线程池中,当代码中
executorService.submit(()->{
System.out.println(Thread.currentThread().getName() + " is running...");
});
执行完后,线程就应该归还给线程池,而这一个动作需要一定的时间,于是我们的sleep方法覆盖了这一时间,当再次执行这段代码块的时候,就会从线程中再取一个,此时线程1已经回到了池中,所以第二次执行时,仍然使用线程1
使用Executors.newFixedThreadPoll()方法
这个方法默认创建的也是控线程池,但是可以在参数中指定线程个数的上限
该实现方法的参数较为复杂,因此我们用一个实际的场景帮助理解
背景:某餐厅有服务员,分为正式员工和临时员工。当顾客特别多的时候,会招聘临时服务员,当顾客较少,等待一段时间之后(确保顾客不会增多了),解雇聘临时服务员,只有正式员工(万恶的资本家)。
我们抽象出如下核心元素——
根据这些抽象元素,我们具体化为参数
参数一:核心线程数量
参数二:最大线程数
参数三:空闲线程最大存活时间
参数四:时间单位 — TimeUnit
参数五:任务队列 — 让任务在队列中等着,等有线程空闲了,再从这个队列中获取任务并执行。
参数六:创建线程工厂 — 按照默认的方式创建线程对象.
参数七:任务的拒绝策略
先看看这个类构造方法的的源码,该构造方法有七个参数,分别是上述三个参数
public class MyThreadPoolExecutor {
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(
2,
5,
2,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(10),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.shutdown();
}
}
上述代码中AbortPolicy()是默认的淘汰策略,表示任务数量超过最大线程数(线程池+等待队列)即丢弃多余的任务。
注意:该方法在丢弃任务后会抛出RejectedExecutionException异常。
特征:丢弃任务,但是不抛出异常这是不推荐的做法。
关键在于“oldest”
特征:抛弃队列中等待最久的任务然后把当前任务加入队列中。
特征:调用任务的run方法绕过线程池直接执行
实现的策略是,当当前线程池无法分配足够的线程执行任务时,将把多余的任务交给别的线程完成
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。