java使用默认线程池踩过的坑(1)(4)
●Thread
- @Override
- protected Object clone() throws CloneNotSupportedException {
- throw new CloneNotSupportedException();
- }
答案显而易见,线程是不支持clone 的。我们需要重新new 一个Thread来重新运行。其实我们只需要将原来的Worker里的Runnable换成我们自己的task,然后将访问权限适当放开就可以了。还有,就是让我们的CustomThreadPoolExecutor继承Thread,因为它需要定时监控自己的所有的worker里Thread的运行状态。
●CustomThreadPoolExecutor
- public class CustomThreadPoolExecutor extends ThreadPoolExecutor implements Runnable {
- public void execute(Testask command) {
- ….//将执行接口改为接收我们的业务类
- }
- …
- …
- private final class Worker
- extends AbstractQueuedSynchronizer
- implements Runnable
- {
- …
- Testask firstTask; //将Runnable改为我们的业务类,方便查看状态
- …
- Worker(Testask firstTask) {
- …//同样将初始化参数改为我们的业务类
- }
- }
- public static void main(String[] args) {
- CustomThreadPoolExecutor pool = new CustomThreadPoolExecutor(0, Integer.MAX_VALUE,
- 60L, TimeUnit.SECONDS,
- new SynchronousQueue<Runnable>());
- Testask task = new Testask();
- task.setInterval(1);
- pool.execute(task);
- Testask task1 = new Testask();
- task1.setInterval(2);
- pool.execute(task1);
- new Thread(pool).start();
- }
- @Override
- public void run() {
- 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 and restart a code task ");
- }
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- }
- }
- }
- }
●Testask
- class Testask implements Runnable {
- …..
- @Override
- public void run() {
- 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() + " after sleep");
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- System.out.println("InterruptedException happens");
- }
- }
- System.out.println("Going to die");
- }
- }
最终方案
综上,最稳妥的就是使用JDK自带的ThreadPoolExecutor, 如果需要对池里的task进行任意时间的控制,可以考虑全面更新,全方面,360度无死角的定制自己的线程池当然是最好的方案,但是一定要注意对于共享对象的处理,适当的处理好并发访问共享对象的方法。
鉴于我们的场景,由于时间紧,而且需要了解的task并不多,暂时选用全部重新更新的策略。上线后,抽时间把自己定制的ThreadPoolExecutor搞定,然后更新上去!
评论暂时关闭