1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package ch.qos.logback.core.util;
16
17 import ch.qos.logback.core.Appender;
18 import ch.qos.logback.core.AppenderBase;
19 import ch.qos.logback.core.Context;
20 import ch.qos.logback.core.ContextBase;
21 import ch.qos.logback.core.spi.AppenderAttachableImpl;
22 import org.junit.jupiter.api.Disabled;
23 import org.junit.jupiter.api.Test;
24
25 import java.util.concurrent.ExecutionException;
26 import java.util.concurrent.ExecutorService;
27 import java.util.concurrent.Executors;
28
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.List;
32 import java.util.concurrent.Future;
33 import java.util.concurrent.locks.ReentrantLock;
34
35 import static org.assertj.core.api.Fail.fail;
36
37 @Disabled
38 public class COWArrayListConcurrencyTest {
39
40
41 private static final int LOOP_LEN = 1_0;
42 private static final int RECONFIGURE_DELAY = 1;
43
44 ReentrantLock reconfigureLock = new ReentrantLock(true);
45 ReentrantLock writeLock = new ReentrantLock(true);
46
47 private static int THREAD_COUNT = 200;
48
49
50 private final ExecutorService tasksExecutor = Executors.newVirtualThreadPerTaskExecutor();
51 LoopingRunnable[] loopingThreads = new LoopingRunnable[THREAD_COUNT];
52 ReconfiguringThread[] reconfiguringThreads = new ReconfiguringThread[THREAD_COUNT];
53 Future<?>[] futures = new Future[THREAD_COUNT];
54
55 AppenderAttachableImpl<String> aai = new AppenderAttachableImpl<>();
56 Context context = new ContextBase();
57
58 void reconfigureWithDelay(AppenderAttachableImpl<String> aai) {
59 try {
60 reconfigureLock.lock();
61 aai.addAppender(makeNewNOPAppender());
62 aai.addAppender(makeNewNOPAppender());
63 delay(RECONFIGURE_DELAY);
64 aai.detachAndStopAllAppenders();
65 } finally {
66 reconfigureLock.unlock();
67 }
68 }
69
70 private Appender<String> makeNewNOPAppender() {
71 List<Long> longList = new ArrayList<>();
72
73
74
75 Appender<String> nopAppenderWithDelay = new NOPAppenderWithDelay<>(longList);
76 nopAppenderWithDelay.setContext(context);
77 nopAppenderWithDelay.start();
78 return nopAppenderWithDelay;
79 }
80
81 private void delay(int delay) {
82 try {
83 Thread.sleep(delay);
84 } catch (InterruptedException e) {
85 throw new RuntimeException(e);
86 }
87 }
88
89 @Test
90 void smoke() throws InterruptedException, ExecutionException {
91
92 for (int i = 0; i < THREAD_COUNT; i++) {
93 System.out.println("i="+i);
94 ReconfiguringThread rt = new ReconfiguringThread(aai);
95 futures[i] = tasksExecutor.submit(rt);
96 reconfiguringThreads[i] = rt;
97 }
98
99 for (int i = 0; i < THREAD_COUNT; i++) {
100 LoopingRunnable loopingThread = new LoopingRunnable(i, aai);
101 tasksExecutor.submit(loopingThread);
102 loopingThreads[i] = loopingThread;
103 }
104
105 for (int i = 0; i < THREAD_COUNT; i++) {
106 futures[i].get();
107 }
108
109
110 Arrays.stream(loopingThreads).forEach(lt -> lt.active = false);
111
112 }
113
114 public class NOPAppenderWithDelay<E> extends AppenderBase<E> {
115
116 List<Long> longList;
117
118 NOPAppenderWithDelay(List<Long> longList) {
119 this.longList = new ArrayList<>(longList);
120 }
121
122 int i = 0;
123
124 @Override
125 protected void append(E eventObject) {
126 i++;
127 try {
128 writeLock.lock();
129 if ((i & 0xF) == 0) {
130 delay(1);
131 } else {
132
133 }
134 } finally {
135 writeLock.unlock();
136 }
137
138 }
139
140 }
141
142 class ReconfiguringThread extends Thread {
143
144 AppenderAttachableImpl<String> aai;
145
146 ReconfiguringThread(AppenderAttachableImpl aai) {
147 this.aai = aai;
148 }
149
150 public void run() {
151 Thread.yield();
152 for (int i = 0; i < LOOP_LEN; i++) {
153 reconfigureWithDelay(aai);
154 }
155 }
156
157
158 }
159
160
161 class LoopingRunnable implements Runnable {
162
163 int num;
164 AppenderAttachableImpl<String> aai;
165 public boolean active = true;
166
167 LoopingRunnable(int num, AppenderAttachableImpl aai) {
168 this.num = num;
169 this.aai = aai;
170 }
171
172 public void run() {
173 System.out.println("LoopingRunnable.run.num="+num);
174 int i = 0;
175 while (active) {
176 if ((i & 0xFFFFF) == 0) {
177 long id = Thread.currentThread().threadId();
178 System.out.println("thread=" + id + " reconfigure=" + i);
179 }
180 aai.appendLoopOnAppenders(Integer.toString(i));
181 i++;
182
183 }
184 }
185 }
186
187
188 }