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

重新启动线程池

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算法-插入排序

    插入排序 一.核心思想:在一个有序的数组中,通过逐一和前面的数进行比较,找到新数的位置. 例子:数组有有一个数21 插入一个3,3<21,因此结果为 3,21 再插入一个34,34>21, ...

  2. kali2018利用ss和ProxyChains实现任意应用代理

    第一步:配置ss 第二步:配置proxychain vim /etc/proxychains.conf 第三步:使用proxychains 终端输入: proxychains firefox 通过代理 ...

  3. wordpress无法登录的解决方法

    使用wordpress建站的朋友可能会遇到wordpress管理密码,有时甚至是正确的密码,但是多次尝试输入都无法登录,并且输入用户名和输入电子邮件都无法获取密码,遇到这种情况怎么办,本文教你如何处理 ...

  4. 【Luogu】P3387缩点(Tarjan缩点+深搜DP)

    题没什么好说的,因为是模板题.求值我用的是dfs. 不能直接在原图上dfs,因为原图上有环的话会发生一些滑稽的事情.所以我们要用Tarjan缩点.因为此题点权全为正,所以如果在图上走一个环当然可以全走 ...

  5. BZOJ 4128 Matrix ——BSGS

    矩阵的BSGS. 只需要哈希一下存起来就可以了. 也并不需要求逆. #include <map> #include <cmath> #include <cstdio> ...

  6. [BZOJ2118] 墨墨的等式(最短路)

    传送门 好神啊.. 需要用非负数个a1,a2,a3...an来凑出B 可以知道,如果一个数x能被凑出来,那么x+a1,x+a2.......x+an也都能被凑出来 那么我们只需要选择a1~an中任意一 ...

  7. net8:简易的文件磁盘管理操作一(包括文件以及文件夹的编辑创建删除移动拷贝重命名等)

    原文发布时间为:2008-08-07 -- 来源于本人的百度文章 [由搬家工具导入] using System;using System.Data;using System.Configuration ...

  8. 转 C++STL之string

    http://www.cnblogs.com/wangkangluo1/archive/2011/07/22/2114118.html string类的构造函数: string(const char ...

  9. Codeforces Round #268 (Div. 2) D. Two Sets [stl - set + 暴力]

    8161957                 2014-10-10 06:12:37     njczy2010     D - Two Sets             GNU C++     A ...

  10. 标准C程序设计七---02

    Linux应用             编程深入            语言编程 标准C程序设计七---经典C11程序设计    以下内容为阅读:    <标准C程序设计>(第7版) 作者 ...