Skip to content

Commit 7ad1bec

Browse files
committed
Expand thread batch util capabilities, offer more generic implementations
1 parent 3f49793 commit 7ad1bec

File tree

4 files changed

+160
-38
lines changed

4 files changed

+160
-38
lines changed

recaf-core/src/main/java/software/coley/recaf/util/threading/Batch.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,39 @@ public interface Batch {
1313
*/
1414
void execute();
1515

16+
/**
17+
* Run the oldest added task. This will remove the task once executed.
18+
*/
19+
void executeOldest();
20+
21+
/**
22+
* Run the newest added task. This will remove the task once executed.
23+
*/
24+
void executeNewest();
25+
1626
/**
1727
* @param runnable
1828
* Task to execute.
1929
*/
2030
void add(@Nonnull Runnable runnable);
2131

2232
/**
23-
* Clears tasks.
33+
* Removes all tasks.
2434
*/
2535
void clear();
36+
37+
/**
38+
* Removes the oldest task.
39+
*/
40+
void removeOldest();
41+
42+
/**
43+
* Removes the newest task.
44+
*/
45+
void removeNewest();
46+
47+
/**
48+
* @return {@code true} when there are no tasks in the batch.
49+
*/
50+
boolean isEmpty();
2651
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package software.coley.recaf.util.threading;
2+
3+
import jakarta.annotation.Nonnull;
4+
5+
import java.util.ArrayList;
6+
import java.util.List;
7+
8+
/**
9+
* A batch implementation that directly runs provided tasks on the calling thread.
10+
*
11+
* @author Matt Coley
12+
*/
13+
public class DirectBatch implements Batch {
14+
private final List<Runnable> tasks = new ArrayList<>();
15+
16+
@Override
17+
public void add(@Nonnull Runnable runnable) {
18+
synchronized (tasks) {
19+
tasks.add(runnable);
20+
}
21+
}
22+
23+
@Override
24+
public void clear() {
25+
synchronized (tasks) {
26+
tasks.clear();
27+
}
28+
}
29+
30+
@Override
31+
public void removeOldest() {
32+
synchronized (tasks) {
33+
tasks.removeFirst();
34+
}
35+
}
36+
37+
@Override
38+
public void removeNewest() {
39+
synchronized (tasks) {
40+
tasks.removeLast();
41+
}
42+
}
43+
44+
@Override
45+
public void execute() {
46+
List<Runnable> tasksCopy;
47+
synchronized (tasks) {
48+
tasksCopy = new ArrayList<>(tasks);
49+
tasks.clear();
50+
}
51+
for (Runnable task : tasksCopy)
52+
task.run();
53+
}
54+
55+
@Override
56+
public void executeOldest() {
57+
Runnable task;
58+
synchronized (tasks) {
59+
if (tasks.isEmpty())
60+
return;
61+
task = tasks.removeFirst();
62+
}
63+
task.run();
64+
}
65+
66+
@Override
67+
public void executeNewest() {
68+
Runnable task;
69+
synchronized (tasks) {
70+
if (tasks.isEmpty())
71+
return;
72+
task = tasks.removeLast();
73+
}
74+
task.run();
75+
}
76+
77+
@Override
78+
public boolean isEmpty() {
79+
synchronized (tasks) {
80+
return tasks.isEmpty();
81+
}
82+
}
83+
}

recaf-core/src/main/java/software/coley/recaf/util/threading/ThreadUtil.java

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,16 @@
55
import org.slf4j.Logger;
66
import software.coley.recaf.analytics.logging.Logging;
77

8-
import java.util.concurrent.*;
8+
import java.util.concurrent.Callable;
9+
import java.util.concurrent.CompletableFuture;
10+
import java.util.concurrent.Executor;
11+
import java.util.concurrent.ExecutorService;
12+
import java.util.concurrent.Future;
13+
import java.util.concurrent.ScheduledExecutorService;
14+
import java.util.concurrent.ScheduledFuture;
15+
import java.util.concurrent.ThreadFactory;
16+
import java.util.concurrent.TimeUnit;
17+
import java.util.concurrent.TimeoutException;
918
import java.util.concurrent.atomic.AtomicBoolean;
1019
import java.util.function.Consumer;
1120
import java.util.function.Supplier;
@@ -362,4 +371,42 @@ public static void shutdown() {
362371
logger.trace("Shutting misc executors");
363372
scheduledService.shutdown();
364373
}
374+
375+
/**
376+
* @return New task batch that executes all actions through the given executor.
377+
*/
378+
@Nonnull
379+
public static Batch batch(@Nonnull Executor executor) {
380+
return new ExecutorBatch(executor);
381+
}
382+
383+
/**
384+
* Batch implementation that executes all tasks on a given executor.
385+
*/
386+
private static class ExecutorBatch extends DirectBatch {
387+
private final Executor executor;
388+
389+
private ExecutorBatch(@Nonnull Executor executor) {
390+
this.executor = executor;
391+
}
392+
393+
@Override
394+
public void execute() {
395+
submit(super::execute);
396+
}
397+
398+
@Override
399+
public void executeOldest() {
400+
submit(super::executeOldest);
401+
}
402+
403+
@Override
404+
public void executeNewest() {
405+
submit(super::executeNewest);
406+
}
407+
408+
private void submit(@Nonnull Runnable execution) {
409+
executor.execute(execution);
410+
}
411+
}
365412
}

recaf-ui/src/main/java/software/coley/recaf/util/FxThreadUtil.java

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import javafx.beans.value.WritableValue;
99
import software.coley.recaf.RecafApplication;
1010
import software.coley.recaf.util.threading.Batch;
11+
import software.coley.recaf.util.threading.DirectBatch;
1112
import software.coley.recaf.util.threading.ThreadPoolFactory;
1213
import software.coley.recaf.util.threading.ThreadUtil;
1314

@@ -113,44 +114,10 @@ public static void onInitialize() {
113114
}
114115

115116
/**
116-
* @return New execution chain.
117+
* @return New task batch that executes all actions on the FX thread.
117118
*/
118119
@Nonnull
119120
public static Batch batch() {
120-
return new FxBatch();
121-
}
122-
123-
/**
124-
* Batch implementation that executes all tasks on the FX thread.
125-
*/
126-
private static class FxBatch implements Batch {
127-
private final List<Runnable> tasks = new ArrayList<>();
128-
129-
@Override
130-
public void add(@Nonnull Runnable runnable) {
131-
synchronized (tasks) {
132-
tasks.add(runnable);
133-
}
134-
}
135-
136-
@Override
137-
public void clear() {
138-
synchronized (tasks) {
139-
tasks.clear();
140-
}
141-
}
142-
143-
@Override
144-
public void execute() {
145-
run(this::fire);
146-
}
147-
148-
private void fire() {
149-
synchronized (tasks) {
150-
for (Runnable task : tasks)
151-
task.run();
152-
tasks.clear();
153-
}
154-
}
121+
return ThreadUtil.batch(jfxExecutor);
155122
}
156123
}

0 commit comments

Comments
 (0)