固安建设局网站,漳州开企网,ngix安装wordpress的伪静态,seo优化软件免费为什么要使用线程池 复习一下创建线程的几种方式#xff1a; 继承Thread 实现Runnable 实现Callable 但是如果频繁的创建/销毁线程#xff0c;就会造成资源浪费。这时候就需要将线程创建好之后存起来#xff0c;以后要用取出来#xff0c;用完后再放回去。
注意 #xff…为什么要使用线程池 复习一下创建线程的几种方式 继承Thread 实现Runnable 实现Callable 但是如果频繁的创建/销毁线程就会造成资源浪费。这时候就需要将线程创建好之后存起来以后要用取出来用完后再放回去。
注意 线程池并不是一种新的线程创建方法它也是靠上面的方式创建线程的只不过它能保存线程实现线程资源的重复利用。
为什么要学线程池效率高牛逼错面试喜欢问。。。
Executor 创建之前首先要来认识一下它 Executor。
Executor是线程池的根接口 3. ThreadPoolExecutor 3.1 七个参数 在创建线程池之前先来看看它的7个参数
new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueueRunnable workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)corePoolSize
线程池核心线程数。
默认情况下核心线程会一直存活即使处于闲置状态也不会受存keepAliveTime限制除非将allowCoreThreadTimeOut设置为true。
maximumPoolSize
线程池所能容纳的最大线程数。超过maximumPoolSize的线程将被阻塞。
最大线程数maximumPoolSize不能小于corePoolSize
keepAliveTime
临时线程的闲置超时时间。超过这个时间临时线程就会被回收。
即 核心线程被创建后一直存活临时线程如果在闲置时间(keepAliveTime)内没有接到新任务会被销毁。
TimeUnit
keepAliveTime的时间单位如TimeUnit.SECONDS。表示keepAliveTime的单位是秒
workQueue
线程池中的任务队列。
没有获得线程资源的任务将会被放入workQueue等待线程资源被释放。
如果核心线程数满了新来的任务会首先放入任务队列
如果任务队列满了会额外创建临时线程完成任务
如果线程数到达最大线程数时任务队列还是满的多余的任务将由RejectedExecutionHandler的拒绝策略进行处理。
常用的有三种队列 SynchronousQueue,LinkedBlockingDeque,ArrayBlockingQueue。
threadFactory
提供创建新线程功能的线程工厂。通过threadFactory程序员可以自定义线程池中线程的创建方法。
ThreadFactory是一个接口只有一个newThread方法
Thread newThread(Runnable r);rejectedExecutionHandler
拒绝策略无法被线程池处理的任务的处理器。
一般是因为任务数超出了workQueue的容量。 3.2 任务队列 常用的三个队列 SynchronousQueue 无界缓冲等待队列。没有容量是不储存元素的阻塞队列会直接将任务交给线程必须等队列中的添加元素表内消费后才能继续添加新的元素。即每次只能装一个任务被线程拿走后才能继续接收任务。 使用SynchronousQueue阻塞队列一般要求最大线程数为无界避免线程拒绝执行操作。 LinkedBlockingDeque无界缓冲等待队列。当前执行的线程数量达到核心线程数时剩余的元素会在阻塞队列里等待即一次性拿走所有任务有多少新来的也能装入等待线程一个一个执行。该队列默认大小为Integer.MAX_VALUE ArrayBlockingQueue 有界缓存等待队列。有容量可以指定缓存队列的大小。只能装指定容量的任务被线程拿走后才能继续装。 3.3 拒绝策略 常用的四个拒绝策略 它们都是ThreadPoolExecutor的内部类 AbortPolicy 丢弃多余任务抛出异常。默认策略。 DiscardPolicy 丢弃新任务不抛出异常。假如新来5个任务想进入队列丢弃他们。 DiscardOldestPolicy 丢弃旧任务不抛出异常。假如新来5个任务想进入队列将任务队列中的前五个丢弃新来的进入队列。 CallerRunsPolicy 不抛弃任务创建线程池的线程帮忙执行任务例如main。 创建线程池 现在就用刚才所学的知识创建一个线程池并让它执行一些任务。
首先创建一个任务类处理响应任务
public class Task implements Runnable{public String name;public Task(String name) {this.name name;}Overridepublic void run() {System.out.println(线程: name 执行任务);}
}紧接着就可以创建线程池这里我们创建一个
核心线程数为2最大线程数为5存活时间为10s队列使用ArrayBlockingQueue拒绝策略使用CallerRunsPolicy创建线程池的线程帮忙执行多余任务
让它处理20个任务
public class Main {public static void main(String[] args) {ThreadPoolExecutor executor new ThreadPoolExecutor(2,5,10,TimeUnit.SECONDS, new ArrayBlockingQueueRunnable(5),new ThreadPoolExecutor.CallerRunsPolicy());for (int i 0; i 20; i) {try {executor.execute(new Task(i ));} catch (Throwable e) {System.out.println(丢弃任务: (i));}}}
}但是也可以注意到任务已经执行结束但是程序还未关闭这就证明线程池并不会主动关闭需要我们调用executor.shutdown()关闭并回收线程池。
public class Main {public static void main(String[] args) {ThreadPoolExecutor executor new ThreadPoolExecutor(2,5,10,TimeUnit.SECONDS, new ArrayBlockingQueueRunnable(5),new ThreadPoolExecutor.CallerRunsPolicy());for (int i 0; i 20; i) {try {executor.execute(new Task(i ));} catch (Throwable e) {System.out.println(丢弃任务: (i));}}executor.shutdown();}
}Executors Java提供了Executors工具类来创建线程池注意它只是一个工具类就像Strings是String的工具类、Objects是Object的工具类一样。Executors创建的线程池都是ExecutorService的实现类。
但是Executors这种方式创建的线程池是JDK提供的有很多细节无法把控所以阿里规范禁止使用Executors来创建线程池。 【强制】线程池不允许使用Executors去创建而是通过ThreadPoolExecutor的方式这样的处理方式让写的同学更加明确线程池的运行规则规避资源耗尽的风险。 说明 Executors返回的线程池对象的弊端如下
1FixedThreadPool和SingleThreadPool:允许的请求队列长度为Integer.MAX_VALUE可能会堆积大量的请求从而导致OOM。
2CachedThreadPool和ScheduledThreadPool:允许的创建线程数量为Integer.MAX_VALUE可能会创建大量的线程从而导致OOM。但是这里依旧要说一下这几种线程池毕竟是官方封装的。而且后面自己写demo也可以直接用。
这几种线程池也是通过new ThreadPoolExecutor() 创建的只不过其中的参数不同所实现的功能也不同。
5.1 CachedThreadPool Executors.newCachedThreadPool()
可缓存线程池如果线程池长度超过处理需要可灵活回收空闲线程若无可回收则新建线程。
public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueueRunnable());
}核心线程数为0任务队列只能装一个任务。也就是 只要来一个任务就创建一个线程处理它来多少任务就创建多少线程。这些线程有60s的存活时间如果接不到新任务就会被回收。
比起手动new线程这个线程池可以实现线程复用、线程超时回收。但是可能创建太多线程造成资源浪费。
5.2 FixedThreadPool Executors.newFixedThreadPool(int nThread)
定长线程池可控制最大并发线程数量超出的线程会在队列中等待。
public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueueRunnable());
}核心线程数 最大线程数核心线程数满了之后任务在队列中等待队列满了之后直接执行拒绝策略而不是创建临时线程因为没有线程。
5.3 SingleThreadExecutor Executors.newSingleThreadExecutor()
单例线程池 只会用唯一的线程工作保证所有任务按照FIFL、LIFO优先级执行。
public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueueRunnable()));
}核心线程数 最大线程数 1只有一个线程所有任务都由它处理任务队列LinkedBlockingQueue可以一次性装很多任务这些任务排着队等待唯一的线程执行。
5.4 ScheduledThreadPoolExecutor 调度线程池定长支持定时及周期性任务执行延迟任务执行。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {return new ScheduledThreadPoolExecutor(corePoolSize);
}
------
public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());
}可以指定核心线程数最大线程数是Integer.MAX_VALUE可以实现延时执行、周期执行。
延时执行
delay 延时时间。
// 参数 : 任务 时间 时间单位
public V ScheduledFutureV schedule(CallableV callable,long delay, TimeUnit unit);周期执行
initialDelay 第一次执行的延时时间 period 每一次执行的间隔时间。
// 参数 : 任务 时间 时间单位
public ScheduledFuture? scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit);ExecutorService 刚刚说了Executors创建的都是ExecutorService的子类那么现在来使用一下ExecutorService完成任务。
先来看看它拥有的方法 shutdown 任务执行完毕后销毁线程池。 shutdownNow 立即销毁线程池。 invokeAll 执行所有任务。 submit 提交并执行任务。
public class TestExecutorService {public static void main(String[] args) {ExecutorService executorService Executors.newCachedThreadPool();for (int i 0; i 10; i) {executorService.submit(() - {System.out.println(Thread.currentThread().getName() 执行);});}System.out.println(executorService.isShutdown());executorService.shutdown();System.out.println(executorService.isShutdown());}
}结果
pool-1-thread-2 执行
pool-1-thread-5 执行
pool-1-thread-6 执行
pool-1-thread-4 执行
pool-1-thread-1 执行
pool-1-thread-3 执行
false
pool-1-thread-8 执行
pool-1-thread-7 执行
pool-1-thread-9 执行
pool-1-thread-4 执行
true
——————