Logback1551.java
/*
* Logback: the reliable, generic, fast and flexible logging framework.
* Copyright (C) 1999-2026, QOS.ch. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v2.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation.
*/
package ch.qos.logback.classic;
import ch.qos.logback.core.util.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class Logback1551 {
LoggerContext lc;
@BeforeEach
public void setUp() throws Exception {
lc = new LoggerContext();
lc.setName("x");
}
@Test
public void testConcurrentModificationScheduledTasks() {
ScheduledExecutorService scheduledExecutorService = lc.getScheduledExecutorService();
Duration duration = Duration.buildByMilliseconds(10);
Runnable runnable = new Runnable() {
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
};
ScheduledFuture<?> scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(runnable,
duration.getMilliseconds(), duration.getMilliseconds(), TimeUnit.MILLISECONDS);
lc.addScheduledFuture(scheduledFuture);
int THREAD_COUNT = 20;
Thread[] threads = new Thread[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; i++) {
threads[i] = new Thread(new CancelRunnable(lc));
threads[i].start();
}
Arrays.stream(threads).forEach(t-> {
try {
t.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
}
private class CancelRunnable implements Runnable {
LoggerContext lc;
public CancelRunnable(LoggerContext lc) {
this.lc = lc;
}
@Override
public void run() {
lc.cancelScheduledTasks();
}
}
}