建设银行官方网站面试详细信息,深圳做网站找哪家好,网站内链建设和外链的推广,cmseasy模板Executor框架
jdk5开始#xff0c;把工作单元与执行机制分离开来#xff0c;工作单元包括Runable和Callable#xff0c;执行机制由Executor框架来提供。
Executor框架简介
Executor框架的两级调度模型
Java线程被一对一映射为本地操作系统线程 java线程启动会创建一个本…Executor框架
jdk5开始把工作单元与执行机制分离开来工作单元包括Runable和Callable执行机制由Executor框架来提供。
Executor框架简介
Executor框架的两级调度模型
Java线程被一对一映射为本地操作系统线程 java线程启动会创建一个本地操作系统线程java线程终止操作系统线程也会被回收操作系统会调度所有线程并将它们分配给可用的cpu 在上层java多线程程序通常把应用分解为若干任务然后使用用户级调度器将这些任务映射为固定数量的线程。在底层操作系统内核将这些线程映射到硬件处理器上应用通过Executor框架控制上层调度下层由操作系统内核控制下层调度不受应用程序控制。 Executor框架的结构与成员
Executor框架结构 主要由任务任务执行和异步计算结果组成 任务包括被执行任务需要实现的接口Runnable和Callable任务的执行包括任务执行机制的核心接口Executor以及继承自Executor的ExecutorServie接口。ThreadPoolExecutor和ScheduledThreadPoolExecutor两个关键类实现了异步计算的结果包括接口Future和实现Future接口的FutureTask类 类和接口 Executor是一个接口是Executor框架的基础将任务的提交与任务的执行分离开来ThreadPoolExecutor是线程池的核心实现类用来执行被提交的任务ScheduledThreadPoolExecutor是一个实现类可以在给定的延迟后运行命令或者定期执行命令。比Timer更灵活功能更强大。Future接口和实现Future接口的FutureTask类代表异步计算的结果Runnable接口和Callable接口的实现类都可以被ThreadPoolExecutor或ScheduledThreadPoolExecutor执行 使用 主线程创建实现Runnable或Callable接口的任务对象工具类Executors可以把一个Runnable对象封装为一个Callable对象Executors.callableRunnable task或Executors.callable(Runnable task,Object result)可以把Runnable对象直接交给ExecutorService执行ExecutorService.execute(Runnable command)或者吧Runnable对象或Callable对象提交给ExecutorService执行ExecutorService.submit(Runnable task)或ExecutorService.submit(Callable task)执行ExecutorService.submit(…)将会返回一个实现Future接口的对象也可以创建FutureTask然后直接交给ExecutorService执行主线程可以执行FutureTask.get()方法来等待任务执行完成。主线程也可以执行FutureTask.cancel来取消此任务
Executor框架的成员 ThreadPoolExecutor通常使用工厂类Executors创建 FixedThreadPool创建固定线程数的FixedThreadPool 适用于为了满足资源管理的需求需要限制当前线程数量的应用场景适用于负载比较重的服务器 public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)SingleThreadExecutor:创建单个线程 适用于需要保证顺序地执行各个任务并且在任意时间点不会有多个线程是活动的应用场景 public static ExecutorService newSingleThreadExecutor()
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)CachedThreadPool:创建一个会根据需要创建新线程 大小无界的线程池适用于执行很多短期异步任务的小程序或负载教轻的服务器 public static ExecutorService newCachedThreadPool()
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory)ScheduledThreadPoolExecutor通常使用工厂类Executors创建 创建ScheduledThreadPoolExecutor包含若干线程的ScheduledThreadPoolExecutor 适用于需要多个后台线程执行周期任务同时为了满足资源管理的需求需要限制后台线程数量的应用场景 public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)创建SingleThreadScheduledExecutor包含一个线程的ScheduledThreadPoolExecutor 适用于需要单个后台线程执行周期任务同时需要保证顺序地执行各个任务的应用场景 public static ScheduledExecutorService newSingleThreadScheduledExecutor(int corePoolSize)
public static ScheduledExecutorService newSingleThreadScheduledExecutor(int corePoolSize, ThreadFactory threadFactory)Future接口 Future接口和Future接口的FutureTask类用来表示异步计算的结果 把Runnable接口或Callable接口的实现类提交给ThreadPoolExecutors或ScheduledThreadPoolExecutors时会返回给一个FutureTask对象 T FutureT submit(CallableT task)
T FutureT submit(Runnable task, T result)
Future submit(Runnable task)Runnable接口和Callable接口 Runnable不会返回结果Callable会返回结果 可以把Runnable包装成Callable public static CallableObject callable(Runnable task)可以把Runnable和一个待返回的结果包装成一个Callable public static T CallableT callable(Runnable task, T result)把callable对象提交给执行时submit会返回一个FutureTask对象 执行get方法等待任务执行完成任务执行完成后get方法将返回该任务的结果
ThreadPoolExecutor详解
构成组件
corePool核心线程池大小maximumPool最大线程池大小BlockingQueue用来暂时保存任务的工作队列RejectedExecutionHandler当ThreadPoolExecutor已经关闭或者饱和时execute方法将要调用的Handler
创建类型
FixedThreadPoolSingleThreadExecutorCachedThreadPool
FixedThreadPool详解
固定线程数线程池
public static ExecutorService newFixedThreadPool(int nThreads){return new ThreadPoolExecutor(nThreads,nThreads, 0L,TimeUnit.MILLISECONDS, new LinkedBlockingQueueRunnable())
}corePoolSize 和maximumPoolSize都被设置为创建FixedThreadPool时指定的参数当啊线程池中的线程数大于corePoolSize时keepAliveTime为多余的空闲线程等待新任务的最长时间超过这个时间后多余的线程将被终止keepAliveTime设置为0多余空闲线程会被立即终止
流程
如果当前运行线程数少于corePoolSize则创建新线程来执行任务在线程池完成预热后当前运行的线程数等于corePoolSize将任务加入LinkedBlockingQueue线程执行完1中的任务后会在循环中反复从LinkedBlockingQueue获取任务执行
使用无界队列LinkedBlockingQueue作为线程池工作队列使用无界队列作为工作队列会对线程池带来影响 当线程池中的线程数达到corePoolSize后新任务将在无界队列中等待因此线程池中的线程数不会超过corePoolSize由于上条使用无界队列时maximumPoolSize将是一个无效参数由于上条和上上条使用无界队列时keepAliveTIme将是一个无效参数由于使用无界队列运行中的FixedThreadPool不会拒绝任务
SingleThreadExecutor详解
使用单个worker线程的Executor
public static ExecutorService newSingleThreadExecutor(){return new ThreadPoolExecutor(1,1, 0L,TimeUnit.MILLISECONDS, new LinkedBlockingQueueRunnable())
}corePoolSize 和maximumPoolSize都被设置为1keepAliveTime设置为0多余空闲线程会被立即终止使用无界队列LinkedBlockingQueue作为线程池的工作队列
工作流程
如果当前运行的线程数少于corePoolSize则创建一个新线程来执行任务在线程池完成预热后将任务加入LinkedBlockingQueue线程执行完1中的任务后会在一个无限循环中反复从LinkedBlockingQueue获取任务来执行
CachedThreadPool详解
根据需要创建新线程的线程池
public static ExecutorService newCachedThreadPool(int nThreads){return new ThreadPoolExecutor(0,Integer.MAX_VALUE, 60L,TimeUnit.MILLISECONDS, new SynchronousQueueRunnable())
}corePoolSize设置为0maximumPoolSize被设置为Integer.MAX_VALUEkeepAliveTime设置为60L线程池中的空闲线程等待新任务的最长时间是60秒空闲线程超过60秒将会被终止使用没有容量的SynchronousQueue作为线程池的工作队列如果主线程提交的任务速度高于maximumPool中线程处理任务的速度时CachedThreadPool会不断创建新线程极端情况下会因为创建过多线程为耗尽cpu和内存资源
流程:
首先执行SynchronousQueue.offer(Runnable task)。如果当前maximumPool中有空闲线程正则执行SynchronousQueue.poll那么主线程执行offer操作与空闲线程执行的poll操作配对成功主线程把任务交给空闲线程执行execute()方法执行完成否则执行步骤2当初始maximumPool为空或者maximumPool中当前没有空闲线程时将没有线程执行SynchronousQueue.poll.这种情况下步骤1 将失败此时CachedThreadPool会创建一个新线程执行任务execute方法执行完成在步骤2中新创建将任务执行完后会执行SynchronousQueue.poll这个poll操作会让空闲线程最多在SynchronousQueue中等待60s如果60s内主线程提交了一个新任务那么这个空闲线程将执行主线程提交的新任务否则这个空闲线程将终止。由于空闲60秒的空闲线程会被终止因此长时间保持空闲的CachedThreadPool不会使用任何资源。
ScheduledThreadPoolExecutor详解
继承自ThreadPoolExecutor主要用来在给定的延迟之后运行任务会定期执行任务。可以在构造函数中指定多个对应的后台线程数
ScheduledThreadPoolExecutor运行机制
DelayQueue是一个无界队列。
主要两部分
当调用ScheduledThreadPoolExecutor的scheduleAtFixedRate方法或者scheduleWithFixedDelay方法时会向ScheduledThreadPoolExecutor的DelayQueue添加一个实现了RunnableScheduledFuture接口的ScheduledFutureTask线程池中的线程从DelayQueue中获取ScheduledFutureTask然后执行任务。
ScheduledThreadPoolExecutor为了实现周期性的执行任务对ThreadPoolExecutor做了如下修改
使用DelayQueue作为任务队列获取任务的方式不同执行周期任务后增加了额外的处理
ScheduledThreadPoolExecutor的实现
ScheduledFutureTask成员变量
long time表示这个任务将要被执行的具体时间long sequenceNumber表示这个任务被添加到ScheduledThreadPoolExecutor中的序号long period表示任务执行的间隔周期
DelayQueue封装了一个优先级队列这个优先级队列会将队列的任务根据time排列小的在前如果time相同比较sequenceNumber小的在前
ScheduledThreadPoolExecutor执行某个周期任务步骤
线程从DelayQueue中获取已到期的ScheduledFutureTask到期任务是指ScheduledFutureTask的time大于等于当前时间 获取Lock获取周期任务 如果PriorityQueue为空当前线程到Condition中等待如果PriorityQueue的头元素的time时间比当前时间大到condition中等待到time时间获取PriorityQueue的头元素如果不为空则唤醒condition中等待的所有线程 释放Lock 线程执行ScheduledFutureTask线程修改ScheduledFutureTask的time后边变为下次将要被执行的时间线程把这个修改time之后的ScheduledFutureTask放回到DelayQueue中 获取Lock添加任务 向PriorityQueue添加任务如果添加的任务是头元素唤醒Condition中等待的所有线程 释放Lock
FutureTask详解
Future接口和实现Future接口的FutureTask类代表异步计算的结果
简介
FutureTask除了实现Future接口外还实现了Runnable接口。FutureTask可以交给Executor执行也可以由调用线程直接执行FutureTask可以处于3种状态 未启动run方法还没有被执行前 执行FutureTask.get将导致调用线程阻塞执行FutureTask.cancel将导致此任务永远不会被执行 已启动run方法被执行过程中 执行FutureTask.get将导致调用线程阻塞执行FutureTask.canceltrue将以中断执行此任务线程的方式来试图停止任务执行FutureTask.cancelfalse将不会对正在执行此任务的线程产生影响 已完成run方法执行完后正常结束或被取消或执行run方法时抛出异常而异常结束 执行FutureTask.get将导致调用线程立即返回结果或抛出异常执行FutureTask.cancel返回false
使用
可以把FutureTask交给Executor执行可以通过ExecutorService.submit返回一个FutureTask然后执行FutureTask.get或cancel方法也可以单独使用FutureTask
当一个线程需要等待另一个线程把某个任务执行完后才能执行此时可以使用FutureTask
实现 基于AQS实现包含两种类型操作 至少一个acquire操作阻塞调用线程除非直到AQS状态允许这线程继续执行FutureTask的acquire操作为get方法调用至少一个release操作这个操作改变AQS的状态改变后的状态可以允许一个或多个阻塞线程被解除阻塞FutureTask的release操作包括run和cancel Sync是FutureTask的内部私有类继承自AQSFutureTask的所有公有方法都直接委托给了内部私有Sync FutureTask.get方法会用AQS的acquireSharedInterruptibly方法执行过程 调用AQS的acquireSharedInterryptibly方法 回调在子类Sync中实现的tryAcquireShared方法来判断acquire操作是否可以成功 成功条件state为执行完成状态RAN或已取消状态CANCELLED且runner不为null 如果成功则get方法立即返回如果失败则到线程等待队列中去等待其他线程执行release操作当其他线程执行release操作唤醒当前线程后当前线程再次执行tryAcquireShared将返回正值1当前线程将离开线程等待队列并唤醒它的后继线程最后返回计算的结果或抛出异常 FutureTask.run方法 执行在构造函数中指定的任务Callable.call以原子方式来更新同步如果这个原则操作成功就设置代表计算结果的变量result的值为callable.call的返回值然后调用AQS.releaseSharedAQS.releaseShared首先会回调在子类Sync中实现的tryReleaseShared来执行release操作AQS.releaseShared然后唤醒线程等待队列中的第一个线程调用FutureTask.done1