简体   繁体   English

即使在ScheduledFuture被取消之后,ThreadPoolExecutor也会运行

[英]ThreadPoolExecutor runs even after ScheduledFuture is cancelled

I'm looking to create a ScheduledThreadPoolExecutor with an unknown pool size. 我想创建一个池大小未知的ScheduledThreadPoolExecutor。 Pool size is determined at run-time, will likely be between 1-5, and for this example I used size 2. We use a custom Task that simply executes a method every so often, but that method will eventually throw an exception (which I've simulated with a simple numTimes variable and if statement). 池大小是在运行时确定的,可能在1-5之间,在本示例中,我使用了大小2。我们使用了一个自定义Task,它每隔一段时间执行一次方法,但是该方法最终会引发异常(我已经用一个简单的numTimes变量和if语句进行了模拟。 If an exception is thrown, I only want to cancel execution of THAT specific thread! 如果抛出异常,我只想取消该特定线程的执行! If all threads are cancelled, I want to shut down the ScheduledThreadPoolExecutor. 如果所有线程都被取消,我想关闭ScheduledThreadPoolExecutor。 Once numTimes == 5 I simulate the exception to cancel the thread), and I can manage to cancel the thread a number of ways but they just don't feel right. 一旦numTimes == 5,我将模拟异常以取消线程),并且我可以通过多种方法设法取消线程,但它们只是感觉不合适。

As a side note, I placed ScheduledFuture everywhere just to play around with cancelling it. 作为附带说明,我将ScheduledFuture放置在各处,只是为了取消它。

    public class Test 
{
  static ScheduledThreadPoolExecutor stpe = new ScheduledThreadPoolExecutor(2);

  public static void main(String[] args) 
  { stpe.scheduleWithFixedDelay(new UpdateTask(1), 0, 1000, TimeUnit.MILLISECONDS);
    stpe.scheduleWithFixedDelay(new UpdateTask(2), 0, 5000, TimeUnit.MILLISECONDS);
//    stpe.shutdown();
  }

  public static class UpdateTask implements Runnable
  {  
     int id;
     int numTimes = 0;
     ScheduledFuture<?> t;

     public UpdateTask(int id)
     { this.id = id;
     }

     public void run()
     { System.out.println("Hello " + id + " num: " + numTimes);
       String fn = "C:\\lib" + id;
       if (numTimes++ == 5)
       { File f = new File(fn);
         f.mkdir();
         t.cancel(false);
       }
     }
  }
}

Calling t.cancel() from run() or from main() have the same effect, in that the thread stops executing but the program does not stop running. 从run()或main()调用t.cancel()具有相同的效果,因为线程停止执行,但程序不会停止运行。 Naturally, this is because the ThreadPoolExecutor is still doing stuff, despite both threads no longer being scheduled. 自然地,这是因为尽管不再调度两个线程,但ThreadPoolExecutor仍在执行操作。

I tried invoking shutdown on stpe, but it doesn't finish thread execution. 我尝试在stpe上调用shutdown,但是它无法完成线程执行。 Two directories are created with stpe.shutdown commented out, and they are not otherwise. 将创建两个目录,其中stpe.shutdown会被注释掉,否则就不会。

I can't figure out an elegant way to cancel ScheduledFuture, then ScheduledThreadPoolExecutor when all ScheduledFuture's are cancelled. 我想不出一种优雅的方式来取消ScheduledFuture,然后取消所有ScheduledFuture时取消ScheduledThreadPoolExecutor。

Final approach ## 最终方法##

I was not able to get s1.get() to work as described in the answer below, so I simply created my own class to handle it. 我无法像下面的答案中所述使s1.get()正常工作,因此我只是创建了自己的类来处理它。

public class Test 
{
  static ScheduledThreadPoolExecutor stpe = new ScheduledThreadPoolExecutor(2);
  static CancelUpdateTasks canceller;

  public static void main(String[] args) 
  { Test t = new Test();
    canceller.add(0, stpe.scheduleWithFixedDelay(new UpdateTask(0), 0, 1000, TimeUnit.MILLISECONDS));
    canceller.add(1, stpe.scheduleWithFixedDelay(new UpdateTask(1), 0, 5000, TimeUnit.MILLISECONDS));
    canceller.waitForSchedules();
    stpe.shutdown();
  }

  public Test() 
  { canceller = new CancelUpdateTasks();
  }

  public static class UpdateTask implements Runnable
  {  
     int id;
     int numTimes = 0;

     public UpdateTask(int id)
     { this.id = id;
     }

     public void run()
     { System.out.println("Hello " + id + " num: " + numTimes);
       if (numTimes++ == 5)
       { canceller.cancel(id);
       }
     }
  }

  public class CancelUpdateTasks 
  { List<ScheduledFuture<?>> scheduler;
    boolean isScheduled;

    public CancelUpdateTasks() 
    { scheduler = new ArrayList<ScheduledFuture<?>>();
      isScheduled = false;
    }

    public void waitForSchedules() 
    { int schedId = 0;
      while(isScheduled)
      { ScheduledFuture<?> schedule = scheduler.get(schedId);
        if (schedule.isCancelled())
        { if (schedId == scheduler.size() - 1)
            return;
          schedId++;
        }
        else
        { try 
          { Thread.sleep(1000);
          } 
          catch (InterruptedException e) 
          { e.printStackTrace();
          }
        }
      }
    }

    public void add(int id, ScheduledFuture<?> schedule) 
    { scheduler.add(id, schedule);
      if (!isScheduled)
        isScheduled = true;
    }

    public void cancel(int id)
    { scheduler.get(id).cancel(false);
    }

    public void cancelNow(int id)
    { scheduler.get(id).cancel(true);
    }
  }
}

You'll want to issue a shutdown on the pool. 您需要关闭该池。 The JVM will continue to run until there are only daemon threads alive. JVM将继续运行,直到只有守护程序线程处于活动状态。 A ThreadPoolExecutor by default will create non-daemon threads. 默认情况下, ThreadPoolExecutor将创建非守护线程。

Just invoke stpe.shutdown(); 只需调用stpe.shutdown();


edit: Based on OPs update 编辑:基于OP更新

shutdown admittedly is different for ScheduledThreadPoolExecugtor than a plain ThreadPoolExecutor. 对于ScheduledThreadPoolExecugtor, shutdown显然不同于普通的ThreadPoolExecutor。 In this case shutdown prevents any scheduled task to become re scheduled. 在这种情况下, shutdown阻止重新安排任何计划的任务。 To make it work correctly you will have to wait on the futures completion. 为了使其正常工作,您将不得不等待期货完成。 You can do so by get() ing on the ScheduledFuture 您可以通过在ScheduledFuture上执行get()来实现

ScheduledFuture sf1 = stpe.scheduleWithFixedDelay(new UpdateTask(1), 0, 1000, TimeUnit.MILLISECONDS);
ScheduledFuture sf2 = stpe.scheduleWithFixedDelay(new UpdateTask(2), 0, 5000, TimeUnit.MILLISECONDS);
sf1.get();
sf2.get();
stpe.shutdown();

In this case both tasks are run asynchronously, the main thread will first wait for sf1 to complete then will wait for sf2 to complete and finally shutdown. 在这种情况下,两个任务都是异步运行的,主线程将首先等待sf1完成,然后将等待sf2完成并最终关闭。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM