J'ai un ScheduledThreadPoolExecutor avec lequel je planifie une tâche à exécuter à un taux fixe. Je veux que la tâche s'exécute avec un délai spécifié pendant au maximum 10 fois jusqu'à ce qu'elle "réussisse". Après cela, je ne voudrai pas que la tâche soit retentée. Donc, fondamentalement, je dois arrêter d'exécuter la tâche planifiée lorsque je veux qu'elle soit arrêtée, mais sans arrêter ScheduledThreadPoolExecutor. Une idée de comment je ferais ça?
Voici un pseudocode -
public class ScheduledThreadPoolExecutorTest
{
public static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(15); // no multiple instances, just one to serve all requests
class MyTask implements Runnable
{
private int MAX_ATTEMPTS = 10;
public void run()
{
if(++attempt <= MAX_ATTEMPTS)
{
doX();
if(doXSucceeded)
{
//stop retrying the task anymore
}
}
else
{
//couldn't succeed in MAX attempts, don't bother retrying anymore!
}
}
}
public void main(String[] args)
{
executor.scheduleAtFixedRate(new ScheduledThreadPoolExecutorTest().new MyTask(), 0, 5, TimeUnit.SECONDS);
}
}
lancez ce test, il imprime 1 2 3 4 5
et s'arrête
public class ScheduledThreadPoolExecutorTest {
static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(15); // no
static ScheduledFuture<?> t;
static class MyTask implements Runnable {
private int attempt = 1;
public void run() {
System.out.print(attempt + " ");
if (++attempt > 5) {
t.cancel(false);
}
}
}
public static void main(String[] args) {
t = executor.scheduleAtFixedRate(new MyTask(), 0, 1, TimeUnit.SECONDS);
}
}
Bien annulé en dehors du fil:
public class ScheduleTest {
@Test
public void testCancel() throws Exception {
final ScheduledThreadPoolExecutor EXECUTOR = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(2);
ScheduledFuture f1 = EXECUTOR.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("Im alive 1");
}
}, 0, 1, TimeUnit.SECONDS);
ScheduledFuture f2 = EXECUTOR.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("Im alive 2");
}
}, 0, 2, TimeUnit.SECONDS);
Thread.sleep(10000);
f1.cancel(true);
System.out.println("f1 cancel");
Thread.sleep(10000);
f2.cancel(false);
System.out.println("f2 cancel");
Thread.sleep(10000);
}
}
Parfois, le fil ne pouvait pas être annulé, cela se résolvait généralement via volatile boolean isCancelled;
CountDownLatch
est une approche alternative. Une fois le thread terminé, appelez countDown()
sur le loquet. Le thread appelant appelle latch.await()
jusqu'à ce que tous les threads soient terminés. À ce stade, appelez ExecutorService.shutdownNow()
pour que votre thread principal ne se transforme pas en zombie.
import Java.util.concurrent.CountDownLatch;
import Java.util.concurrent.Executors;
import Java.util.concurrent.ScheduledExecutorService;
import Java.util.concurrent.TimeUnit;
public class ScheduledThreadPoolExecutorTest {
static int i = 0;
public static void main(String[] args) throws Exception {
final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
final CountDownLatch latch = new CountDownLatch(1);
executor.scheduleAtFixedRate(() -> {
System.out.println(++i);
if (i > 4) {
latch.countDown();
}
}, 0, 100, TimeUnit.MILLISECONDS);
latch.await();
executor.shutdownNow();
}
}