Skip to content

Commit 630b03e

Browse files
committed
Virtual Thread for AsyncScheduler
1 parent b9c461f commit 630b03e

File tree

1 file changed

+312
-0
lines changed

1 file changed

+312
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2+
From: HaHaWTH <id_cn00@outlook.com>
3+
Date: Fri, 5 Apr 2024 11:47:01 +0800
4+
Subject: [PATCH] virtual-thread-for-AsyncScheduler
5+
6+
7+
diff --git a/src/main/java/com/github/ruviolence/reaper/BeastConfig.java b/src/main/java/com/github/ruviolence/reaper/BeastConfig.java
8+
index 5ed1e87ab91adcf7f49025747c8567e093f551a2..6a4a1a4b15ff0a52704d9ea18be896fe8dfc648a 100644
9+
--- a/src/main/java/com/github/ruviolence/reaper/BeastConfig.java
10+
+++ b/src/main/java/com/github/ruviolence/reaper/BeastConfig.java
11+
@@ -150,6 +150,12 @@ public class BeastConfig {
12+
RegionFile.deflater.setLevel(chunkCompressionLevel);
13+
}
14+
15+
+ public static boolean virtualThreadForScheduler;
16+
+
17+
+ private static void virtualThreadForScheduler() {
18+
+ virtualThreadForScheduler = getBoolean("virtual-thread-for-scheduler", false);
19+
+ }
20+
+
21+
public static int portalTravelCacheLife;
22+
public static boolean portalTravelInstantExpire;
23+
private static void portalTravel() {
24+
diff --git a/src/main/java/com/homomc/beast/virtualthreads/DirectVirtualThreadService.java b/src/main/java/com/homomc/beast/virtualthreads/DirectVirtualThreadService.java
25+
new file mode 100644
26+
index 0000000000000000000000000000000000000000..6bb13e68e92c3d940bd114a3ab9af14c73a0df99
27+
--- /dev/null
28+
+++ b/src/main/java/com/homomc/beast/virtualthreads/DirectVirtualThreadService.java
29+
@@ -0,0 +1,46 @@
30+
+package com.homomc.beast.virtualthreads;
31+
+
32+
+
33+
+import java.util.concurrent.ThreadFactory;
34+
+
35+
+/**
36+
+ * An implementation of {@link VirtualThreadService} that can create virtual threads directly.
37+
+ *
38+
+ */
39+
+final class DirectVirtualThreadService extends VirtualThreadService {
40+
+
41+
+ private DirectVirtualThreadService() {
42+
+ super();
43+
+ }
44+
+
45+
+ @Override
46+
+ public ThreadFactory createFactory() {
47+
+ // Disabled until Minecraft requires servers to have a Java version that can read class files compiled with functionality from Java 19+ on preview / Java 21+ on stable
48+
+ throw new UnsupportedOperationException();
49+
+// return Thread.ofVirtual().factory();
50+
+ }
51+
+
52+
+ @Override
53+
+ public Thread start( Runnable task) {
54+
+ // Disabled until Minecraft requires servers to have a Java version that can read class files compiled with functionality from Java 19+ on preview / Java 21+ on stable
55+
+ throw new UnsupportedOperationException();
56+
+// Objects.requireNonNull(task, "The task to start a virtual thread cannot be null");
57+
+// return Thread.ofVirtual().start(task);
58+
+ }
59+
+
60+
+ /**
61+
+ * @return A functional {@link DirectVirtualThreadService}.
62+
+ * @throws Throwable If creating virtual threads directly is not supported by the current runtime.
63+
+ * This could be any {@link Throwable}, including an {@link Exception} or an {@link Error}.
64+
+ */
65+
+ static DirectVirtualThreadService create() throws Throwable {
66+
+ // Disabled until Minecraft requires servers to have a Java version that can read class files compiled with functionality from Java 19+ on preview / Java 21+ on stable
67+
+ throw new UnsupportedOperationException();
68+
+// var service = new DirectVirtualThreadService();
69+
+// // Run some tests to verify
70+
+// service.runTest();
71+
+// // If we end up here, it works
72+
+// return service;
73+
+ }
74+
+
75+
+}
76+
\ No newline at end of file
77+
diff --git a/src/main/java/com/homomc/beast/virtualthreads/ReflectionVirtualThreadService.java b/src/main/java/com/homomc/beast/virtualthreads/ReflectionVirtualThreadService.java
78+
new file mode 100644
79+
index 0000000000000000000000000000000000000000..f12f96eb793ad8fc0d1c2a4bd461031e841064f0
80+
--- /dev/null
81+
+++ b/src/main/java/com/homomc/beast/virtualthreads/ReflectionVirtualThreadService.java
82+
@@ -0,0 +1,71 @@
83+
+package com.homomc.beast.virtualthreads;
84+
+
85+
+import java.lang.reflect.Method;
86+
+import java.util.Objects;
87+
+import java.util.concurrent.ThreadFactory;
88+
+
89+
+/**
90+
+ * An implementation of {@link VirtualThreadService} that can create virtual threads using Java reflection.
91+
+ *
92+
+ */
93+
+final class ReflectionVirtualThreadService extends VirtualThreadService {
94+
+
95+
+ /**
96+
+ * The {@link Thread}#ofVirtual() method.
97+
+ */
98+
+ private final Method Thread_ofVirtual_method;
99+
+
100+
+ /**
101+
+ * The {@link Thread}.Builder#factory() method.
102+
+ */
103+
+ private final Method Thread_Builder_factory_method;
104+
+
105+
+ /**
106+
+ * The {@link Thread}.Builder#start(Runnable) method.
107+
+ */
108+
+ private final Method Thread_Builder_start_method;
109+
+
110+
+ private ReflectionVirtualThreadService() throws Throwable {
111+
+ this.Thread_ofVirtual_method = Objects.requireNonNull(Thread.class.getMethod("ofVirtual"));
112+
+ // The Thread.Builder class
113+
+ Class<?> Thread_Builder_class = Objects.requireNonNull(Class.forName("java.lang.Thread$Builder"));
114+
+ this.Thread_Builder_factory_method = Objects.requireNonNull(Thread_Builder_class.getMethod("factory"));
115+
+ this.Thread_Builder_start_method = Objects.requireNonNull(Thread_Builder_class.getMethod("start", Runnable.class));
116+
+ }
117+
+
118+
+ @Override
119+
+ public ThreadFactory createFactory() {
120+
+ try {
121+
+ return (ThreadFactory) this.Thread_Builder_factory_method.invoke(this.Thread_ofVirtual_method.invoke(null));
122+
+ } catch (Exception e) {
123+
+ // This should not be possible because it was tested in create()
124+
+ throw new RuntimeException(e);
125+
+ }
126+
+ }
127+
+
128+
+ @Override
129+
+ public Thread start( Runnable task) {
130+
+ Objects.requireNonNull(task, "The task to start a virtual thread cannot be null");
131+
+ try {
132+
+ return (Thread) this.Thread_Builder_start_method.invoke(this.Thread_ofVirtual_method.invoke(null), task);
133+
+ } catch (Exception e) {
134+
+ // This should not be possible because it was tested in create()
135+
+ throw new RuntimeException(e);
136+
+ }
137+
+ }
138+
+
139+
+ /**
140+
+ * @return A functional {@link ReflectionVirtualThreadService}.
141+
+ * @throws Throwable If creating virtual threads via reflection is not supported by the current runtime.
142+
+ * This could be any {@link Throwable}, including an {@link Exception} or an {@link Error}.
143+
+ */
144+
+ static ReflectionVirtualThreadService create() throws Throwable {
145+
+ // This will already throw something if the reflection fails
146+
+ ReflectionVirtualThreadService service = new ReflectionVirtualThreadService();
147+
+ // Run some tests to verify
148+
+ service.runTest();
149+
+ // If we end up here, it works
150+
+ return service;
151+
+ }
152+
+
153+
+}
154+
\ No newline at end of file
155+
diff --git a/src/main/java/com/homomc/beast/virtualthreads/VirtualThreadService.java b/src/main/java/com/homomc/beast/virtualthreads/VirtualThreadService.java
156+
new file mode 100644
157+
index 0000000000000000000000000000000000000000..91ff46293e9a82be0f935851f87b7d4108ec5eac
158+
--- /dev/null
159+
+++ b/src/main/java/com/homomc/beast/virtualthreads/VirtualThreadService.java
160+
@@ -0,0 +1,94 @@
161+
+package com.homomc.beast.virtualthreads;
162+
+
163+
+import java.util.concurrent.ThreadFactory;
164+
+
165+
+/**
166+
+ * An abstract service to create virtual threads.
167+
+ */
168+
+public abstract class VirtualThreadService {
169+
+
170+
+ /**
171+
+ * @return A {@link ThreadFactory} that produces virtual threads.
172+
+ */
173+
+ public abstract ThreadFactory createFactory();
174+
+
175+
+ /**
176+
+ * @param task The runnable for the thread to execute.
177+
+ * @return A virtual thread that has been started with the given task.
178+
+ */
179+
+ public abstract Thread start(Runnable task);
180+
+
181+
+ /**
182+
+ * Runs a test on the {@link #createFactory} and {@link #start} methods,
183+
+ * which certainly throws some {@link Throwable} if something goes wrong.
184+
+ */
185+
+ protected void runTest() throws Throwable {
186+
+ // This will definitely throw something if it doesn't work
187+
+ try {
188+
+ this.start(() -> {}).join();
189+
+ } catch (InterruptedException ignored) {} // Except InterruptedException, we don't care about that one
190+
+ try {
191+
+ Thread thread = this.createFactory().newThread(() -> {});
192+
+ thread.start();
193+
+ thread.join();
194+
+ } catch (InterruptedException ignored) {} // Except InterruptedException, we don't care about that one
195+
+ // If we end up here, it works
196+
+ }
197+
+
198+
+ private static boolean initialized = false;
199+
+
200+
+ /**
201+
+ * The {@link VirtualThreadService} for the current runtime,
202+
+ * or null if virtual threads are not supported, or if not {@link #initialized} yet.
203+
+ */
204+
+ private static VirtualThreadService implementation;
205+
+
206+
+ /**
207+
+ * @return Whether virtual threads are supported on the current runtime.
208+
+ */
209+
+ public static boolean isSupported() {
210+
+ return get() != null;
211+
+ }
212+
+
213+
+ /**
214+
+ * @return The {@link VirtualThreadService} for the current runtime,
215+
+ * or null if virtual threads are not {@linkplain #isSupported() supported}.
216+
+ *
217+
+ * This method is thread-safe only after the first time it has been fully run.
218+
+ */
219+
+ public static VirtualThreadService get() {
220+
+ if (!initialized) {
221+
+ initialized = true;
222+
+ try {
223+
+ implementation = DirectVirtualThreadService.create();
224+
+ } catch (Throwable ignored) {
225+
+ try {
226+
+ implementation = ReflectionVirtualThreadService.create();
227+
+ } catch (Throwable ignored2) {}
228+
+ }
229+
+ }
230+
+ return implementation;
231+
+ }
232+
+
233+
+ /**
234+
+ * The minimum major version of Java that is known to support using virtual threads
235+
+ * (although possibly behind a feature preview flag).
236+
+ */
237+
+ public static final int minimumJavaMajorVersionWithFeaturePreview = 19;
238+
+
239+
+ /**
240+
+ * The minimum major version of Java that is known to support using virtual threads
241+
+ * even without any feature preview flags.
242+
+ */
243+
+ public static final int minimumJavaMajorVersionWithoutFeaturePreview = 21;
244+
+
245+
+ public static int getJavaMajorVersion() {
246+
+ String version = System.getProperty("java.version");
247+
+ if (version.startsWith("1.")) {
248+
+ return version.charAt(2) - '0';
249+
+ }
250+
+ int dotIndex = version.indexOf(".");
251+
+ return Integer.parseInt(dotIndex == -1 ? version : version.substring(0, dotIndex));
252+
+ }
253+
+
254+
+}
255+
\ No newline at end of file
256+
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java
257+
index eaf8692877d95170f87cc637c30e72419206b970..06fbebbb4b4e7789e50e348304e5e311f3b8d7a4 100644
258+
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java
259+
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java
260+
@@ -25,30 +25,42 @@ package org.bukkit.craftbukkit.scheduler;
261+
262+
import com.destroystokyo.paper.ServerSchedulerReportingWrapper;
263+
import com.google.common.util.concurrent.ThreadFactoryBuilder;
264+
+import com.homomc.beast.virtualthreads.VirtualThreadService;
265+
import org.bukkit.plugin.Plugin;
266+
267+
+import java.lang.reflect.Method;
268+
import java.util.ArrayList;
269+
import java.util.Iterator;
270+
import java.util.List;
271+
-import java.util.concurrent.Executor;
272+
-import java.util.concurrent.Executors;
273+
-import java.util.concurrent.SynchronousQueue;
274+
-import java.util.concurrent.ThreadPoolExecutor;
275+
-import java.util.concurrent.TimeUnit;
276+
+import java.util.concurrent.*;
277+
278+
public class CraftAsyncScheduler extends CraftScheduler {
279+
280+
- private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
281+
- 4, Integer.MAX_VALUE,30L, TimeUnit.SECONDS, new SynchronousQueue<>(),
282+
- new ThreadFactoryBuilder().setNameFormat("Craft Scheduler Thread - %1$d").build());
283+
+ private Executor executor;
284+
private final Executor management = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder()
285+
.setNameFormat("Craft Async Scheduler Management Thread").build());
286+
private final List<CraftTask> temp = new ArrayList<>();
287+
288+
CraftAsyncScheduler() {
289+
super(true);
290+
- executor.allowCoreThreadTimeOut(true);
291+
- executor.prestartAllCoreThreads();
292+
+ if (VirtualThreadService.getJavaMajorVersion() >= VirtualThreadService.minimumJavaMajorVersionWithoutFeaturePreview && com.github.ruviolence.reaper.BeastConfig.virtualThreadForScheduler) {
293+
+ try {
294+
+ Method newThreadPerTaskExecutor = Executors.class.getMethod("newThreadPerTaskExecutor", ThreadFactory.class);
295+
+ executor = (Executor) newThreadPerTaskExecutor.invoke(null, VirtualThreadService.get().createFactory());
296+
+ return;
297+
+ } catch (Exception ignored) {
298+
+ System.err.println("Failed to create Virtual Thread executor! Fallback to default executor.");
299+
+ }
300+
+ }
301+
+
302+
+ executor = new ThreadPoolExecutor(
303+
+ 4, Integer.MAX_VALUE, 30L, TimeUnit.SECONDS, new SynchronousQueue<>(),
304+
+ new ThreadFactoryBuilder().setNameFormat("Craft Scheduler Thread - %1$d").build());
305+
+
306+
+ ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
307+
+
308+
+ threadPoolExecutor.allowCoreThreadTimeOut(true);
309+
+ threadPoolExecutor.prestartAllCoreThreads();
310+
}
311+
312+
@Override

0 commit comments

Comments
 (0)