202 // unexpectedly, so we can force that condition too by shutting down our custom scheduler.
203 private static Thread.Builder.OfVirtual virtualThreadBuilder(Executor scheduler) {
204 Thread.Builder.OfVirtual builder = Thread.ofVirtual();
205 try {
206 Class<?> clazz = Class.forName("java.lang.ThreadBuilders$VirtualThreadBuilder");
207 Constructor<?> ctor = clazz.getDeclaredConstructor(Executor.class);
208 ctor.setAccessible(true);
209 return (Thread.Builder.OfVirtual) ctor.newInstance(scheduler);
210 } catch (InvocationTargetException e) {
211 Throwable cause = e.getCause();
212 if (cause instanceof RuntimeException re) {
213 throw re;
214 }
215 throw new RuntimeException(e);
216 } catch (Exception e) {
217 throw new RuntimeException(e);
218 }
219 }
220
221 static void runTest(int nThreads, boolean skipUnlock, boolean throwOnExit) throws Throwable {
222 final Object monitor = new Object();
223 final AtomicReference<Throwable> exception = new AtomicReference();
224 // Ensure all our VT's operate of the same carrier, sequentially.
225 ExecutorService scheduler = Executors.newSingleThreadExecutor();
226 ThreadFactory factory = virtualThreadBuilder(scheduler).factory();
227 for (int i = 0 ; i < nThreads; i++) {
228 Thread th = factory.newThread(() -> {
229 try {
230 int res = monitorEnter(monitor);
231 Asserts.assertTrue(res == 0, "monitorEnter should return 0.");
232 Asserts.assertTrue(Thread.holdsLock(monitor), "monitor should be owned");
233 Thread.yield();
234 if (!skipUnlock) {
235 res = monitorExit(monitor);
236 Asserts.assertTrue(res == 0, "monitorExit should return 0.");
237 Asserts.assertFalse(Thread.holdsLock(monitor), "monitor should be unowned");
238 }
239 } catch (Throwable t) {
240 exception.set(t);
241 }
242 if (throwOnExit) {
243 throw new RuntimeException(throwMsg);
244 }
245 });
246 th.start();
247 th.join();
|
202 // unexpectedly, so we can force that condition too by shutting down our custom scheduler.
203 private static Thread.Builder.OfVirtual virtualThreadBuilder(Executor scheduler) {
204 Thread.Builder.OfVirtual builder = Thread.ofVirtual();
205 try {
206 Class<?> clazz = Class.forName("java.lang.ThreadBuilders$VirtualThreadBuilder");
207 Constructor<?> ctor = clazz.getDeclaredConstructor(Executor.class);
208 ctor.setAccessible(true);
209 return (Thread.Builder.OfVirtual) ctor.newInstance(scheduler);
210 } catch (InvocationTargetException e) {
211 Throwable cause = e.getCause();
212 if (cause instanceof RuntimeException re) {
213 throw re;
214 }
215 throw new RuntimeException(e);
216 } catch (Exception e) {
217 throw new RuntimeException(e);
218 }
219 }
220
221 static void runTest(int nThreads, boolean skipUnlock, boolean throwOnExit) throws Throwable {
222 final Object[] monitors = new Object[nThreads];
223 for (int i = 0; i < nThreads; i++) {
224 monitors[i] = new Object();
225 }
226 final AtomicReference<Throwable> exception = new AtomicReference();
227 // Ensure all our VT's operate of the same carrier, sequentially.
228 ExecutorService scheduler = Executors.newSingleThreadExecutor();
229 ThreadFactory factory = virtualThreadBuilder(scheduler).factory();
230 for (int i = 0 ; i < nThreads; i++) {
231 Object monitor = skipUnlock ? monitors[i] : monitors[0];
232 Thread th = factory.newThread(() -> {
233 try {
234 int res = monitorEnter(monitor);
235 Asserts.assertTrue(res == 0, "monitorEnter should return 0.");
236 Asserts.assertTrue(Thread.holdsLock(monitor), "monitor should be owned");
237 Thread.yield();
238 if (!skipUnlock) {
239 res = monitorExit(monitor);
240 Asserts.assertTrue(res == 0, "monitorExit should return 0.");
241 Asserts.assertFalse(Thread.holdsLock(monitor), "monitor should be unowned");
242 }
243 } catch (Throwable t) {
244 exception.set(t);
245 }
246 if (throwOnExit) {
247 throw new RuntimeException(throwMsg);
248 }
249 });
250 th.start();
251 th.join();
|