diff --git a/forge-core/src/main/java/forge/util/ThreadUtil.java b/forge-core/src/main/java/forge/util/ThreadUtil.java index 4ec6fb0f0a9..fd49e51506e 100644 --- a/forge-core/src/main/java/forge/util/ThreadUtil.java +++ b/forge-core/src/main/java/forge/util/ThreadUtil.java @@ -20,10 +20,8 @@ public class ThreadUtil { } } - // Use a single game thread, rather than a pool of them, because when something - // needs to execute on the game thread, it's because it's not thread safe. - private final static ExecutorService gameThread = Executors.newSingleThreadExecutor(new WorkerThreadFactory("Game")); - private static ExecutorService getGameThreadPool() { return gameThread; } + private final static ExecutorService gameThreadPool = Executors.newCachedThreadPool(new WorkerThreadFactory("Game")); + private static ExecutorService getGameThreadPool() { return gameThreadPool; } private final static ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(2, new WorkerThreadFactory("Delayed")); private static ScheduledExecutorService getScheduledPool() { return scheduledPool; } diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index 83bf3505205..b035731f1f2 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -17,7 +17,6 @@ */ package forge.game; -import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Iterables; @@ -77,7 +76,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import java.util.concurrent.Callable; /** * Methods for common actions performed during a game. @@ -1746,17 +1744,8 @@ public class GameAction { // state effects are checked only when someone gets priority } - private Function invokeFunction; - public synchronized void setInvokeFunction(Function invokeFunction) { - this.invokeFunction = invokeFunction; - } - - // Invokes given runnable on the Game thread - used to start game and perform actions from UI when waiting for input. - public synchronized void invoke(final Runnable proc) { - if (invokeFunction != null) { - invokeFunction.apply(proc); - return; - } + // Invokes given runnable in Game thread pool - used to start game and perform actions from UI (when game-0 waits for input) + public void invoke(final Runnable proc) { if (ThreadUtil.isGameThread()) { proc.run(); } diff --git a/forge-gui/src/main/java/forge/match/input/InputSyncronizedBase.java b/forge-gui/src/main/java/forge/match/input/InputSyncronizedBase.java index d916514c1b4..9ca2f6ce712 100644 --- a/forge-gui/src/main/java/forge/match/input/InputSyncronizedBase.java +++ b/forge-gui/src/main/java/forge/match/input/InputSyncronizedBase.java @@ -1,34 +1,25 @@ package forge.match.input; -import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.CountDownLatch; -import com.google.common.base.Function; import forge.FThreads; import forge.error.BugReporter; import forge.player.PlayerControllerHuman; -import forge.util.ThreadUtil; public abstract class InputSyncronizedBase extends InputBase implements InputSynchronized { private static final long serialVersionUID = 8756177361251703052L; - private static final Runnable terminationMarker = new Runnable() { public void run() { } }; - - // The gameTaskQueue indicates tasks to run while blocked on the game. To stop, add terminationMarker (as null is - // not allowed). - private LinkedBlockingDeque gameTaskQueue = new LinkedBlockingDeque(); + private final CountDownLatch cdlDone; public InputSyncronizedBase(final PlayerControllerHuman controller) { super(controller); + cdlDone = new CountDownLatch(1); } @Override public void awaitLatchRelease() { FThreads.assertExecutedByEdt(false); - try { - Runnable r = gameTaskQueue.take(); - while (r != terminationMarker) { - r.run(); - r = gameTaskQueue.take(); - } + try{ + cdlDone.await(); } catch (final InterruptedException e) { BugReporter.reportException(e); } @@ -36,34 +27,12 @@ public abstract class InputSyncronizedBase extends InputBase implements InputSyn @Override public final void relaseLatchWhenGameIsOver() { - gameTaskQueue.add(terminationMarker); + cdlDone.countDown(); } public void showAndWait() { - final boolean isGameThread = ThreadUtil.isGameThread(); - - if (isGameThread) { - // If we're on the game thread, redirect the "run on game thread" function to instead go through us. - getController().getGame().getAction().setInvokeFunction(new Function() { - public Void apply(Runnable r) { - gameTaskQueue.add(r); - return null; - } - }); - } - getController().getInputQueue().setInput(this); awaitLatchRelease(); - - if (isGameThread) { - // Reset the invoke function to null. - getController().getGame().getAction().setInvokeFunction(null); - // There's a race that a new task may be queued up before we've reset the invoke function. - // To handle this, schedule any remaining tasks normally. - for (Runnable r : gameTaskQueue) { - getController().getGame().getAction().invoke(r); - } - } } protected final void stop() { @@ -81,7 +50,7 @@ public abstract class InputSyncronizedBase extends InputBase implements InputSyn if (getController().getInputQueue().getInput() != null) { getController().getInputQueue().removeInput(InputSyncronizedBase.this); } - gameTaskQueue.add(terminationMarker); + cdlDone.countDown(); } protected void onStop() { }