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

重新启动线程池

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. 二丶人生苦短,我用python【第二篇】

    1 编码 python解释器在加载 .py 文件中的代码时,对内容默认进行ascill编码,因此存在中文会报错,所以需要告诉python解释器,用什么编码来执行源代码.) ASCII码,主要用于显示现 ...

  2. TOJ 4095: love168yk的选美大赛

    4095: love168yk的选美大赛  Time Limit(Common/Java):1000MS/3000MS     Memory Limit:65536KByteTotal Submit: ...

  3. TOJ 4475: The Coolest Sub-matrix

    4475: The Coolest Sub-matrix  Time Limit(Common/Java):4000MS/12000MS     Memory Limit:65536KByteTota ...

  4. BZOJ 4810 [Ynoi2017]由乃的玉米田 ——Bitset 莫队算法

    加法和减法的操作都能想到Bitset. 然后发现乘法比较难办,反正复杂度已经是$O(n\log{n})$了 枚举因数也不能更差了,直接枚举就好了. #include <map> #incl ...

  5. POJ 2914 Minimum Cut 全局最小割

    裸的全局最小割了吧 有重边,用邻接矩阵的时候要小心 #include<iostream> #include<cstdio> #include<bitset> #in ...

  6. 浅谈中途相遇攻击--meet-in-the-middle attack

    貌似挖的坑也够多了....好多都没填,这篇最后会不会TJ还得看心情TUT 看过大白书的人应该都会发现一种神奇的算法:中途相遇法.(在第58页)这种算法将以空间换时间的思路运用到了极致,但事实上它在密码 ...

  7. POJ 1502 MPI Maelstrom【floyd】

    题目大意:求点1到所有点最短路径的最大值 思路:水题,单源最短路,网上解题清一色dijkstra,但是点数小于100显然floyd更简洁嘛 #include<cstdio> #includ ...

  8. jenkins异常解答

    1.安装插件时offline 需要更换插件管理中的升级URL   http://mirror.xmission.com/jenkins/updates/current/update-center.js ...

  9. HDU 3001 三进制 状压dp

    Travelling Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  10. PHP输出控制函数(ob系列函数)

    PHP输出控制函数(ob系列函数) flush — 刷新输出缓冲ob_clean — 清空(擦掉)输出缓冲区ob_end_clean — 清空(擦除)缓冲区并关闭输出缓冲ob_end_flush — ...