云智慧(北京)科技有限公司  陈鑫

重新启动线程池

TaskManager

public class TaskManager implements Runnable {

…..

public TaskManager (Setrunners) {

super();

this.runners = runners;

executeTasks(runners);

}

private voidexecuteTasks(Set<FileTask> runners) {
for (FileTask task : runners){
pool.execute(task);
System.out.println(task.getClass().getSimpleName() + " has beenstarted");
}
} @Override
public void run() {
while(!Thread.currentThread().isInterrupted()) {
try {
long current = System.currentTimeMillis();
for (FileTask wrapper : runners) {
if (wrapper.getLastExecTime() != 0 && current -wrapper.getLastExecTime() > wrapper.getInterval() * 5 * 1000) { // 開始忘了乘以1000
wrapper.interrupt();
if (wrapper.getFiles() != null){
for (File file : wrapper.getFiles()){
file.delete();
}
}
System.out.println("Going to shutdown thethread pool");
List<Runnable> shutdownNow = pool.shutdownNow(); // 不等当前pool里的任务运行完。直接关闭线程池
for (Runnable run : shutdownNow) {
System.out.println(run + " goingto be shutdown");
}
while (pool.awaitTermination(1, TimeUnit.SECONDS)) {
System.out.println("The threadpool has been shutdown " + new Date());
executeTasks(runners);//又一次运行
Thread.sleep(200);
}
}
}
} catch(Exception e1) {
e1.printStackTrace();
}
try {
Thread.sleep(500);
} catch(InterruptedException e) {
}
}
}
public static void main(String[] args) {
Set<FileTask> tasks =new HashSet<FileTask>(); FileTask task = newFileTask();
task.setInterval(1);
task.setName("task-1");
tasks.add(task); FileTask task1 = newFileTask();
task1.setInterval(2);
task.setName("task-2");
tasks.add(task1); TaskManager codeManager = new TaskManager (tasks);
newThread(codeManager).start();
}

}

成功。把整个的ThreadPoolExector里所有的worker所有停止,之后再向其队列里又一次增加要运行的两个task(注意这里并没有清空,仅仅是停止而已)。这样做尽管能够及时处理task,可是一个非常致命的缺点在于。假设不能明白的知道ThreadPoolExecutor要运行的task。就没有办法又一次运行这些任务。

定制线程池

好吧!停止钻研别人的东西!

我们全然能够自己写一个自己的ThreadPoolExecutor。仅仅要把worker暴露出来就能够了。这里是不是回忆起前面的start问题来了,没错。我们即便能够直接针对Thread进行interrupt, 可是不能再次start它了。那么clone一个相同的Thread行不行呢?

Thread

@Override

protectedObject clone() throws CloneNotSupportedException{

throw newCloneNotSupportedException();

}

答案显而易见。线程是不支持clone 的。

我们须要又一次new 一个Thread来又一次运行。事实上我们仅仅须要将原来的Worker里的Runnable换成我们自己的task,然后将訪问权限适当放开就能够了。

还有,就是让我们的CustomThreadPoolExecutor继承Thread,由于它须要定时监控自己的所有的worker里Thread的运行状态。

CustomThreadPoolExecutor

public class CustomThreadPoolExecutor extendsThreadPoolExecutor implements Runnable {

public voidexecute(Testask command) {

….//将运行接口改为接收我们的业务类

}





private final class Worker

extends AbstractQueuedSynchronizer

implements Runnable

{



Testask firstTask; //将Runnable改为我们的业务类,方便查看状态



Worker(Testask firstTask) {

…//相同将初始化參数改为我们的业务类

}

}

public staticvoid main(String[] args) {

CustomThreadPoolExecutor pool = new CustomThreadPoolExecutor(0, Integer.MAX_VALUE,

60L, TimeUnit.SECONDS,

newSynchronousQueue());

    Testasktask = new Testask();
task.setInterval(1);
pool.execute(task); Testasktask1 = new Testask();
task1.setInterval(2);
pool.execute(task1); newThread(pool).start();
} @Override
public voidrun() {
while(!Thread.currentThread().isInterrupted()) {
try {
long current = System.currentTimeMillis();
Set<Testask> toReExecute = new HashSet<Testask>();
System.out.println("\t number is " + number);
for(Worker wrapper : workers) {
Testask tt = wrapper.firstTask;
if (tt != null) {
if (current - tt.getLastExecTime() > tt.getInterval() * 5 * 1000) {

wrapper.interruptIfStarted();

remove(tt);

if (tt.getFiles() != null) {

for (File file: tt.getFiles()) {

file.delete();

}

}

System.out.println(“THread is timeout : ” + tt + ” “+ new Date());

toReExecute.add(tt);

}

}

}

if(toReExecute.size() > 0) {

mainLock.lock();

try {

for (Testask tt :toReExecute) {

execute(tt); // execute this task again

}

} finally {

mainLock.unlock();

}

}

} catch(Exception e1) {

System.out.println(“Error happens when we trying to interrupt andrestart a code task “);

}

try {

Thread.sleep(500);

} catch(InterruptedException e) {

}

}

}

}

Testask

class Testask implements Runnable {

…..

@Override
public voidrun() {
while(!Thread.currentThread().isInterrupted()) {
lastExecTime = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName() + " is running-> " + new Date());
try {
CustomThreadPoolExecutor.number++;
Thread.sleep(getInterval() * 6 * 1000);
System.out.println(Thread.currentThread().getName() + " aftersleep");
} catch(InterruptedException e) {

Thread.currentThread().interrupt();

System.out.println(“InterruptedException happens”);

}

}

System.out.println(“Going to die”);

}

}

终于方案

综上,最稳妥的就是使用JDK自带的ThreadPoolExecutor,假设须要对池里的task进行随意时间的控制,能够考虑全面更新,全方面,360度无死角的定制自己的线程池当然是最好的方案。可是一定要注意对于共享对象的处理,适当的处理好并发訪问共享对象的方法。

鉴于我们的场景。由于时间紧,并且须要了解的task并不多。临时选用所有又一次更新的策略。

上线后。抽时间把自己定制的ThreadPoolExecutor搞定,然后更新上去!

java使用默认线程池踩过的坑(三)的更多相关文章

  1. java使用默认线程池踩过的坑(二)

    云智慧(北京)科技有限公司 陈鑫 是的.一个线程不可以启动两次.那么它是怎么推断的呢? public synchronized void start() { /** * A zero status v ...

  2. 不要使用Java Executors 提供的默认线程池

    线程池构造方法 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUni ...

  3. Java 四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor

    介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端执行一个异步任务你还只是如下new T ...

  4. Java四种线程池

    Java四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor 时间:20 ...

  5. Java多线程和线程池

    转自:http://blog.csdn.net/u013142781/article/details/51387749 1.为什么要使用线程池 在Java中,如果每个请求到达就创建一个新线程,开销是相 ...

  6. Java多线程之线程池详解

    前言 在认识线程池之前,我们需要使用线程就去创建一个线程,但是我们会发现有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因 ...

  7. Java四种线程池的学习与总结

    在Java开发中,有时遇到多线程的开发时,直接使用Thread操作,对程序的性能和维护上都是一个问题,使用Java提供的线程池来操作可以很好的解决问题. 一.new Thread的弊端 执行一个异步任 ...

  8. java多线程、线程池及Spring配置线程池详解

    1.java中为什么要使用多线程使用多线程,可以把一些大任务分解成多个小任务来执行,多个小任务之间互不影像,同时进行,这样,充分利用了cpu资源.2.java中简单的实现多线程的方式 继承Thread ...

  9. Java高并发 -- 线程池

    Java高并发 -- 线程池 主要是学习慕课网实战视频<Java并发编程入门与高并发面试>的笔记 在使用线程池后,创建线程变成了从线程池里获得空闲线程,关闭线程变成了将线程归坏给线程池. ...

随机推荐

  1. 自己项目使用了ARC,项目中使用第三方库继续引用ARC

    Objective-C引入ARC(Automatic Reference Counting)后,我们经常会面对这样一种困境:自己的项目使用了ARC,却发现要使用的第三方类库是non-ARC的:又或者自 ...

  2. openscad 3Dmodels 笔记

    参考链接 官方文档 官方文档之--代码 如何快速上手 打开openSCAD后界面如下: 选择其中的examples,从basic看起.配合官方文档中的first step部分,和官方文档--代码写法即 ...

  3. selenium之定位以及切换frame

    总有人看不明白,以防万一,先在开头大写加粗说明一下: frameset不用切,frame需层层切! 很多人在用selenium定位页面元素的时候会遇到定位不到的问题,明明元素就在那儿,用firebug ...

  4. Linux cp复制

    复制指定目录下的全部文件到另一个目录中文件及目录的复制是经常要用到的.linux下进行复制的命令为cp.假设复制源目录 为 dir1 ,目标目录为dir2.怎样才能将dir1下所有文件复制到dir2下 ...

  5. [UOJ#127][BZOJ4195][NOI2015]程序自动分析

    [UOJ#127][BZOJ4195][NOI2015]程序自动分析 试题描述 在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足. 考虑一个约束满足问题的简化版本:假设x1,x2, ...

  6. BZOJ 4650 [Noi2016]优秀的拆分 ——后缀数组

    我们只需要统计在某一个点开始的形如$AA$字符串个数,和结束的个数相乘求和. 首先枚举循环节的长度L.即$\mid (A) \mid=L$ 然后肯定会经过s[i]和[i+L]至少两个点. 然后我们可以 ...

  7. 洛谷P2498 [SDOI2012]拯救小云公主 【二分 + 并查集】

    题目 英雄又即将踏上拯救公主的道路-- 这次的拯救目标是--爱和正义的小云公主. 英雄来到boss的洞穴门口,他一下子就懵了,因为面前不只是一只boss,而是上千只boss.当英雄意识到自己还是等级1 ...

  8. 刷题总结——随机图(ssoi)

    题目: 随机图 (random.cpp/c/pas) [问题描述] BG 为了造数据,随机生成了一张�个点的无向图.他把顶点标号为1~�. 根据BG 的随机算法,对于一个点对�, �(1 ≤ � &l ...

  9. 稻草人(bzoj 4237)

    Description JOI村有一片荒地,上面竖着N个稻草人,村民们每年多次在稻草人们的周围举行祭典. 有一次,JOI村的村长听到了稻草人们的启示,计划在荒地中开垦一片田地.和启示中的一样,田地需要 ...

  10. 使用 ftrace 调试 Linux 内核,第 2 部分

    ftrace 操作概述 使用 ftrace 提供的跟踪器来调试或者分析内核时需要如下操作: 切换到目录 /sys/kernel/debug/tracing/ 下 查看 available_tracer ...