TimeoutFutureTask实现
来源:互联网 发布:缩略图软件下载 编辑:程序博客网 时间:2024/06/04 19:28
Java1.5的java.util.concurrent
包封装了一系列异步处理操作的工具,简化了多线程程序的开发。其中一个重要的工具类就是Executors。
通过他提供的工厂方法我们可以很方便的就生成线程池的实例,例如获取一个固定线程池大小的实例只需要调用Executors.newFixedThreadPool(MAX_THREAD_COUNT)
,其中MAX_THREAD_COUNT
就是我们需要的线程池大小。这个方法其实是生成了一个ThreadPool的实例
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
再看看ThreadPoolExecutor的完整构造方法
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
corePoolSize是指可以运行的核心线程数量,maximumPoolSize是指可以运行的最大线程数量,keepAliveTime是指如果线程数量超过了核心线程数量的那部分线程(既maximumPoolSize-corePoolSize那部分)如果空闲的最大存活时间,意即在超过这个时间之后只保留核心线程数量的线程继续在后台中等待执行,让系统的开销变得更加合理,最后一个参数RejectedExecutionHandler是指如果线程无法进入等待队列的拒绝处理(拒绝策略),其他几个参数就不再一一介绍了。
通过Executors.newFixedThreadPool生成的线程池一旦核心线程都处于运行中的时候,接下来的线程要么继续被加入等待队列中(因为未制定等待线程的容量,所以线程都会被加入等待队列中),要么被拒绝。如果核心线程池中的线程永远不退出,那么新加入的线程则永远无法执行,在我们目前的项目中就碰到了这样的情况。怎么办?修改策略,与其让他们一直占用着资源,不如让这些流氓退出,让新的线程进可以继续执行。
于是我们实现了一个FutureTask的子类TimeoutFutureTask来作为扩充:
private static class TimeoutFutureTask<V> extends FutureTask<V> { private long startTime = System.currentTimeMillis(); public TimeoutFutureTask(Callable<V> callable) { super(callable); } public TimeoutFutureTask(Runnable runnable, V result) { super(runnable, result); } public boolean isExpire() { return System.currentTimeMillis() - startTime > MAX_EXECUTION_TIME; } }
这里主要引入了一个额外的属性private long startTime = System.currentTimeMillis();
通过记录线程创建时间,通过它计算计算线程是否过期isExpire()
。
再引入一个线程放在static代码块内(让这个线程随着第一个线程被启动时启动在后台):
private static final long MAX_EXECUTION_TIME = 10 * 60 * 1000; private static final Vector<TimeoutFutureTask> FUTURE_TASK_VECTOR = new Vector<>(); private volatile static boolean IS_CHECK_THREAD_STARTED = false; static { if (!IS_CHECK_THREAD_STARTED) { new Thread(new Runnable() { @Override public void run() { IS_CHECK_THREAD_STARTED = true; while (FUTURE_TASK_VECTOR != null) { try { System.out.println("Check thread."); try { Thread.sleep(MAX_EXECUTION_TIME); } catch (InterruptedException e) { e.printStackTrace(); } Iterator<TimeoutFutureTask> iterator = FUTURE_TASK_VECTOR.iterator(); while (iterator.hasNext()) { TimeoutFutureTask task = iterator.next(); System.out.printf("Task start at: %s%n", new Date(task.startTime)); try { if (task.isExpire()) { System.out.println("Task expired."); iterator.remove(); if (task.isDone() || task.isCancelled()) { continue; } task.cancel(true); } } catch (Exception e) { e.printStackTrace(); } } } catch (Exception e) { e.printStackTrace(); } } IS_CHECK_THREAD_STARTED = false; } }).start(); } }
一旦线程超时未被执行就取消(这里的检查时间间隔MAX_EXECUTION_TIME,考虑到最坏情况,线程最多的存活时间:MAX_EXECUTION_TIME*2)
if (task.isExpire()) { System.out.println("Task expired."); iterator.remove(); if (task.isDone() || task.isCancelled()) { continue; } task.cancel(true);}
这样就解决了超时线程在合理的时间超时退出的问题。
下一步还应该继续优化处理报告,需要有一个超时报告,将超时的线程信息写日志做分析。
- TimeoutFutureTask实现
- 实现
- 实现
- 红黑树实现 实现代码
- java实现排列组合实现
- 实现Runnable 实现线程
- 实现ViewPager多种实现
- 双向LSTM实现实现
- 实现缓存 java实现
- 三子棋的实现的实现的实现
- 四则运算实现
- 继承实现
- 重载实现
- 实现缩略图
- split实现
- 实现缩略图
- wmi实现
- 实现缩略图
- Zoj 3646 Matrix Transformer 二分图完美匹配
- Docker镜像和容器操作(一)
- hdu 5349 MZL's simple problem
- HDU 2846 Repository(字典树)
- C++数据结构之Linked Stack(链式栈)
- TimeoutFutureTask实现
- Codeforces Round #318 (Div. 2) D - Bear and Blocks
- wxWidgets和QT之间的选择
- 链表翻转的递归和非递归实现
- ZOJ 2112 Dynamic Rankings 树状数组套主席树 单点修改求动态区间第K大
- 读书笔记之深入理解操作系统(10)
- 三种单例模式的C++实现
- CodeForces 337A - Puzzles
- redis的学习地址