1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package ch.qos.logback.classic;
16
17 import ch.qos.logback.core.util.Duration;
18 import org.junit.jupiter.api.BeforeEach;
19 import org.junit.jupiter.api.Test;
20
21 import java.util.Arrays;
22 import java.util.concurrent.ScheduledExecutorService;
23 import java.util.concurrent.ScheduledFuture;
24 import java.util.concurrent.TimeUnit;
25
26 public class Logback1551 {
27 LoggerContext lc;
28
29 @BeforeEach
30 public void setUp() throws Exception {
31 lc = new LoggerContext();
32 lc.setName("x");
33 }
34 @Test
35 public void testConcurrentModificationScheduledTasks() {
36 ScheduledExecutorService scheduledExecutorService = lc.getScheduledExecutorService();
37 Duration duration = Duration.buildByMilliseconds(10);
38
39 Runnable runnable = new Runnable() {
40 public void run() {
41 try {
42 Thread.sleep(100);
43 } catch (InterruptedException e) {
44 throw new RuntimeException(e);
45 }
46 }
47 };
48 ScheduledFuture<?> scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(runnable,
49 duration.getMilliseconds(), duration.getMilliseconds(), TimeUnit.MILLISECONDS);
50
51 lc.addScheduledFuture(scheduledFuture);
52 int THREAD_COUNT = 20;
53 Thread[] threads = new Thread[THREAD_COUNT];
54
55 for (int i = 0; i < THREAD_COUNT; i++) {
56 threads[i] = new Thread(new CancelRunnable(lc));
57 threads[i].start();
58 }
59
60 Arrays.stream(threads).forEach(t-> {
61 try {
62 t.join();
63 } catch (InterruptedException e) {
64 throw new RuntimeException(e);
65 }
66 });
67
68 }
69
70 private class CancelRunnable implements Runnable {
71 LoggerContext lc;
72 public CancelRunnable(LoggerContext lc) {
73 this.lc = lc;
74 }
75
76 @Override
77 public void run() {
78 lc.cancelScheduledTasks();
79 }
80 }
81 }