Skip to content

Commit 1793e46

Browse files
committed
Use mini2Dx-lock-provider for concurrency
1 parent 777acac commit 1793e46

13 files changed

+434
-30
lines changed

CHANGES

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
[1.6.0]
2+
- Use mini2Dx-lock-provider for concurrency
3+
14
[1.5.3]
25
- Add wfc() alias for waitForCompletion()
36

build.gradle

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ subprojects {
4646

4747
bcelVersion='5.2'
4848
javaPoetVersion='1.11.1'
49-
49+
lockProviderVersion='1.1.0'
50+
5051
junitVersion='4.11'
5152
jmockVersion='2.5.1'
5253
}
@@ -144,6 +145,8 @@ project(":" + rootProject.name + "-core") {
144145
description = "miniscript core library"
145146

146147
dependencies {
148+
compile "org.mini2Dx:mini2Dx-lock-provider:$lockProviderVersion"
149+
147150
testCompile "junit:junit:$junitVersion"
148151
testCompile "org.jmock:jmock-junit4:$jmockVersion"
149152
testCompile "org.jmock:jmock-legacy:$jmockVersion"

core/src/main/java/org/mini2Dx/miniscript/core/GameFuture.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@
2323
*/
2424
package org.mini2Dx.miniscript.core;
2525

26+
import org.mini2Dx.miniscript.core.exception.ScriptSkippedException;
27+
2628
import java.util.concurrent.atomic.AtomicBoolean;
2729
import java.util.concurrent.atomic.AtomicInteger;
2830

29-
import org.mini2Dx.miniscript.core.exception.ScriptSkippedException;
30-
3131
/**
3232
* Represents a task that will complete in-game at a future time
3333
*/

core/src/main/java/org/mini2Dx/miniscript/core/GameScriptingEngine.java

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,22 @@
2323
*/
2424
package org.mini2Dx.miniscript.core;
2525

26-
import java.io.IOException;
27-
import java.io.InputStream;
28-
import java.util.HashSet;
29-
import java.util.Map;
30-
import java.util.Queue;
31-
import java.util.Scanner;
32-
import java.util.Set;
33-
import java.util.concurrent.*;
34-
import java.util.concurrent.atomic.AtomicBoolean;
35-
26+
import org.mini2Dx.lockprovider.Locks;
27+
import org.mini2Dx.lockprovider.jvm.JvmLocks;
3628
import org.mini2Dx.miniscript.core.exception.InsufficientCompilersException;
3729
import org.mini2Dx.miniscript.core.exception.NoSuchScriptException;
3830
import org.mini2Dx.miniscript.core.notification.ScriptNotification;
31+
import org.mini2Dx.miniscript.core.util.ReadWriteArrayQueue;
32+
import org.mini2Dx.miniscript.core.util.ReadWriteMap;
33+
import org.mini2Dx.miniscript.core.util.ReadWritePriorityQueue;
34+
35+
import java.io.IOException;
36+
import java.io.InputStream;
37+
import java.util.*;
38+
import java.util.concurrent.Future;
39+
import java.util.concurrent.ScheduledFuture;
40+
import java.util.concurrent.TimeUnit;
41+
import java.util.concurrent.atomic.AtomicBoolean;
3942

4043
/**
4144
* Provides scripting functionality to your game
@@ -48,13 +51,15 @@ public abstract class GameScriptingEngine implements Runnable {
4851
*/
4952
public static GameScriptingEngine MOST_RECENT_INSTANCE = null;
5053

54+
public static Locks LOCK_PROVIDER = new JvmLocks();
55+
5156
private final ScriptInvocationPool scriptInvocationPool = new ScriptInvocationPool();
52-
private final Queue<ScriptInvocation> scriptInvocations = new PriorityBlockingQueue<>(64);
53-
final Queue<ScriptNotification> scriptNotifications = new ConcurrentLinkedQueue<ScriptNotification>();
57+
private final Queue<ScriptInvocation> scriptInvocations = new ReadWritePriorityQueue<>();
58+
final Queue<ScriptNotification> scriptNotifications = new ReadWriteArrayQueue<ScriptNotification>();
5459

55-
final Queue<GameFuture> queuedFutures = new ConcurrentLinkedQueue<GameFuture>();
56-
final Map<Integer, GameFuture> runningFutures = new ConcurrentHashMap<Integer, GameFuture>();
57-
private final Map<Integer, ScriptExecutionTask<?>> runningScripts = new ConcurrentHashMap<Integer, ScriptExecutionTask<?>>();
60+
final Queue<GameFuture> queuedFutures = new ReadWriteArrayQueue<>();
61+
final Map<Integer, GameFuture> runningFutures = new ReadWriteMap<Integer, GameFuture>();
62+
private final Map<Integer, ScriptExecutionTask<?>> runningScripts = new ReadWriteMap<Integer, ScriptExecutionTask<?>>();
5863
private final Set<Integer> completedFutures = new HashSet<Integer>();
5964
private final Set<Integer> completedScripts = new HashSet<Integer>();
6065

core/src/main/java/org/mini2Dx/miniscript/core/PerThreadClasspathGameScript.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@
2323
*/
2424
package org.mini2Dx.miniscript.core;
2525

26+
import org.mini2Dx.miniscript.core.util.ReadWriteMap;
27+
2628
import java.util.Map;
27-
import java.util.concurrent.ConcurrentHashMap;
2829

2930
public class PerThreadClasspathGameScript<S> extends GameScript<S> {
30-
private final Map<Long, S> threadToScriptMapping = new ConcurrentHashMap<Long, S>();
31+
private final Map<Long, S> threadToScriptMapping = new ReadWriteMap<>();
3132
private final S content;
3233

3334
public PerThreadClasspathGameScript(S content) {

core/src/main/java/org/mini2Dx/miniscript/core/PerThreadGameScript.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,16 @@
2323
*/
2424
package org.mini2Dx.miniscript.core;
2525

26+
import org.mini2Dx.miniscript.core.util.ReadWriteMap;
27+
2628
import java.util.Map;
27-
import java.util.concurrent.ConcurrentHashMap;
2829

2930
/**
3031
* An implementation of {@link GameScript} for language runtimes where
3132
* a script must be compiled on a per thread basis
3233
*/
3334
public class PerThreadGameScript<S> extends GameScript<S> {
34-
private final Map<Long, S> threadToScriptMapping = new ConcurrentHashMap<Long, S>();
35+
private final Map<Long, S> threadToScriptMapping = new ReadWriteMap<>();
3536
private final String content;
3637

3738
public PerThreadGameScript(String content) {

core/src/main/java/org/mini2Dx/miniscript/core/ScriptBindings.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
package org.mini2Dx.miniscript.core;
2525

2626
import java.util.*;
27-
import java.util.concurrent.ConcurrentHashMap;
28-
import java.util.concurrent.atomic.AtomicInteger;
2927

3028
/**
3129
* A mapping of variable names to objects passed to a script

core/src/main/java/org/mini2Dx/miniscript/core/ScriptExecutionTask.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@
2323
*/
2424
package org.mini2Dx.miniscript.core;
2525

26-
import java.util.concurrent.Future;
27-
import java.util.concurrent.atomic.AtomicBoolean;
28-
import java.util.concurrent.atomic.AtomicInteger;
29-
3026
import org.mini2Dx.miniscript.core.exception.ScriptSkippedException;
3127
import org.mini2Dx.miniscript.core.notification.ScriptExceptionNotification;
3228
import org.mini2Dx.miniscript.core.notification.ScriptSkippedNotification;
3329
import org.mini2Dx.miniscript.core.notification.ScriptSuccessNotification;
3430

31+
import java.util.concurrent.Future;
32+
import java.util.concurrent.atomic.AtomicBoolean;
33+
import java.util.concurrent.atomic.AtomicInteger;
34+
3535
/**
3636
* Executes a script
3737
*/

core/src/main/java/org/mini2Dx/miniscript/core/ScriptInvocationPool.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,16 @@
2323
*/
2424
package org.mini2Dx.miniscript.core;
2525

26+
import org.mini2Dx.miniscript.core.util.ReadWriteArrayQueue;
27+
2628
import java.util.Queue;
27-
import java.util.concurrent.ConcurrentLinkedQueue;
2829

2930
/**
3031
* Provides a pool of reusable {@link ScriptInvocation} instances to reduce
3132
* object allocation
3233
*/
3334
public class ScriptInvocationPool {
34-
private final Queue<ScriptInvocation> pool = new ConcurrentLinkedQueue<ScriptInvocation>();
35+
private final Queue<ScriptInvocation> pool = new ReadWriteArrayQueue<>();
3536

3637
/**
3738
* Allocate a {@link ScriptInvocation} instance
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/**
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2020 Thomas Cashman
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
package org.mini2Dx.miniscript.core.util;
25+
26+
import org.mini2Dx.lockprovider.ReadWriteLock;
27+
import org.mini2Dx.miniscript.core.GameScriptingEngine;
28+
29+
import java.util.Collection;
30+
import java.util.Iterator;
31+
import java.util.Queue;
32+
33+
public abstract class AbstractConcurrentQueue<E> implements Queue<E> {
34+
private final ReadWriteLock lock = GameScriptingEngine.LOCK_PROVIDER.newReadWriteLock();
35+
36+
private final Queue<E> internalQueue;
37+
38+
public AbstractConcurrentQueue(Queue<E> internalQueue) {
39+
this.internalQueue = internalQueue;
40+
}
41+
42+
@Override
43+
public int size() {
44+
lock.lockRead();
45+
final int result = internalQueue.size();
46+
lock.unlockRead();
47+
return result;
48+
}
49+
50+
@Override
51+
public boolean isEmpty() {
52+
return size() == 0;
53+
}
54+
55+
@Override
56+
public boolean contains(Object o) {
57+
lock.lockRead();
58+
final boolean result = internalQueue.contains(o);
59+
lock.unlockRead();
60+
return result;
61+
}
62+
63+
@Override
64+
public Iterator<E> iterator() {
65+
throw new UnsupportedOperationException();
66+
}
67+
68+
@Override
69+
public Object[] toArray() {
70+
lock.lockRead();
71+
try {
72+
return internalQueue.toArray();
73+
} finally {
74+
lock.unlockRead();
75+
}
76+
}
77+
78+
@Override
79+
public <T> T[] toArray(T[] a) {
80+
lock.lockRead();
81+
try {
82+
return internalQueue.toArray(a);
83+
} finally {
84+
lock.unlockRead();
85+
}
86+
}
87+
88+
@Override
89+
public boolean add(E e) {
90+
lock.lockWrite();
91+
final boolean result = internalQueue.add(e);
92+
lock.unlockWrite();
93+
return result;
94+
}
95+
96+
@Override
97+
public boolean remove(Object o) {
98+
lock.lockWrite();
99+
final boolean result = internalQueue.remove(o);
100+
lock.unlockWrite();
101+
return result;
102+
}
103+
104+
@Override
105+
public boolean containsAll(Collection<?> c) {
106+
lock.lockRead();
107+
final boolean result = internalQueue.containsAll(c);
108+
lock.unlockRead();
109+
return result;
110+
}
111+
112+
@Override
113+
public boolean addAll(Collection<? extends E> c) {
114+
lock.lockWrite();
115+
final boolean result = internalQueue.addAll(c);
116+
lock.unlockWrite();
117+
return result;
118+
}
119+
120+
@Override
121+
public boolean removeAll(Collection<?> c) {
122+
lock.lockWrite();
123+
final boolean result = internalQueue.removeAll(c);
124+
lock.unlockWrite();
125+
return result;
126+
}
127+
128+
@Override
129+
public boolean retainAll(Collection<?> c) {
130+
lock.lockWrite();
131+
final boolean result = internalQueue.retainAll(c);
132+
lock.unlockWrite();
133+
return result;
134+
}
135+
136+
@Override
137+
public void clear() {
138+
lock.lockWrite();
139+
internalQueue.clear();
140+
lock.unlockWrite();
141+
}
142+
143+
@Override
144+
public boolean offer(E e) {
145+
return add(e);
146+
}
147+
148+
@Override
149+
public E remove() {
150+
lock.lockWrite();
151+
try {
152+
return internalQueue.remove();
153+
} finally {
154+
lock.unlockWrite();
155+
}
156+
}
157+
158+
@Override
159+
public E poll() {
160+
lock.lockWrite();
161+
try {
162+
return internalQueue.poll();
163+
} finally {
164+
lock.unlockWrite();
165+
}
166+
}
167+
168+
@Override
169+
public E element() {
170+
lock.lockRead();
171+
try {
172+
return internalQueue.element();
173+
} finally {
174+
lock.unlockRead();
175+
}
176+
}
177+
178+
@Override
179+
public E peek() {
180+
lock.lockRead();
181+
try {
182+
return internalQueue.peek();
183+
} finally {
184+
lock.unlockRead();
185+
}
186+
}
187+
}

0 commit comments

Comments
 (0)