SynchronizedMap: Allow multiple reading operations at the same time

This commit is contained in:
Bixilon 2021-11-12 19:11:52 +01:00
parent 86155c8f3f
commit 441b4e9550
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
4 changed files with 125 additions and 91 deletions

View File

@ -14,6 +14,7 @@
package de.bixilon.minosoft.data.world.container package de.bixilon.minosoft.data.world.container
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.SemaphoreLock
open class SectionDataProvider<T>( open class SectionDataProvider<T>(
data: Array<Any?> = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION), data: Array<Any?> = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION),

View File

@ -104,12 +104,14 @@ object KUtil {
} }
fun <K, V> Map<K, V>.toSynchronizedMap(): SynchronizedMap<K, V> { fun <K, V> Map<K, V>.toSynchronizedMap(): SynchronizedMap<K, V> {
val lock = if (this is SynchronizedMap<*, *>) { return if (this is SynchronizedMap<*, *>) {
this.lock lock.acquire()
val map: SynchronizedMap<K, V> = SynchronizedMap(this.toMutableMap()).unsafeCast()
lock.release()
map
} else { } else {
null synchronizedCopy { SynchronizedMap(this.toMutableMap()) }
} }
return synchronizedCopy(lock) { SynchronizedMap(this.toMutableMap()) }
} }
fun <V> Collection<V>.toSynchronizedList(): MutableList<V> { fun <V> Collection<V>.toSynchronizedList(): MutableList<V> {

View File

@ -11,7 +11,7 @@
* This software is not affiliated with Mojang AB, the original developer of Minecraft. * This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/ */
package de.bixilon.minosoft.data.world.container package de.bixilon.minosoft.util
import java.util.concurrent.Semaphore import java.util.concurrent.Semaphore

View File

@ -15,6 +15,7 @@ package de.bixilon.minosoft.util.collections
import de.bixilon.minosoft.util.KUtil.toSynchronizedList import de.bixilon.minosoft.util.KUtil.toSynchronizedList
import de.bixilon.minosoft.util.KUtil.toSynchronizedSet import de.bixilon.minosoft.util.KUtil.toSynchronizedSet
import de.bixilon.minosoft.util.SemaphoreLock
import java.util.function.BiConsumer import java.util.function.BiConsumer
import java.util.function.BiFunction import java.util.function.BiFunction
import java.util.function.Function import java.util.function.Function
@ -22,171 +23,201 @@ import java.util.function.Function
class SynchronizedMap<K, V>( class SynchronizedMap<K, V>(
private val original: MutableMap<K, V>, private val original: MutableMap<K, V>,
) : MutableMap<K, V> { ) : MutableMap<K, V> {
internal val lock = Object() internal val lock = SemaphoreLock()
override val size: Int override val size: Int
get() = synchronized(lock) { original.size } get() {
lock.acquire()
val returnValue = original.size
lock.release()
return returnValue
}
override fun containsKey(key: K): Boolean { override fun containsKey(key: K): Boolean {
synchronized(lock) { lock.acquire()
return original.containsKey(key) val returnValue = original.containsKey(key)
} lock.release()
return returnValue
} }
override fun containsValue(value: V): Boolean { override fun containsValue(value: V): Boolean {
synchronized(lock) { lock.acquire()
return original.containsValue(value) val returnValue = original.containsValue(value)
} lock.release()
return returnValue
} }
override fun get(key: K): V? { override fun get(key: K): V? {
synchronized(lock) { lock.acquire()
return original[key] val returnValue = original[key]
} lock.release()
return returnValue
} }
override fun isEmpty(): Boolean { override fun isEmpty(): Boolean {
synchronized(lock) { lock.acquire()
return original.isEmpty() val returnValue = original.isEmpty()
} lock.release()
return returnValue
} }
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
get() { get() {
synchronized(lock) { lock.acquire()
return original.entries.toSynchronizedSet() val returnValue = original.entries.toSynchronizedSet()
} lock.release()
return returnValue
} }
override val keys: MutableSet<K> override val keys: MutableSet<K>
get() { get() {
synchronized(lock) { lock.acquire()
return original.keys.toSynchronizedSet() val returnValue = original.keys.toSynchronizedSet()
} lock.release()
return returnValue
} }
override val values: MutableCollection<V> override val values: MutableCollection<V>
get() { get() {
synchronized(lock) { lock.acquire()
return original.values.toSynchronizedList() val returnValue = original.values.toSynchronizedList()
} lock.release()
return returnValue
} }
override fun clear() { override fun clear() {
synchronized(lock) { lock.lock()
original.clear() original.clear()
} lock.unlock()
} }
override fun put(key: K, value: V): V? { override fun put(key: K, value: V): V? {
synchronized(lock) { lock.lock()
return original.put(key, value) val returnValue = original.put(key, value)
} lock.unlock()
return returnValue
} }
override fun putAll(from: Map<out K, V>) { override fun putAll(from: Map<out K, V>) {
synchronized(lock) { lock.lock()
return original.putAll(from) val returnValue = original.putAll(from)
} lock.unlock()
return returnValue
} }
override fun remove(key: K): V? { override fun remove(key: K): V? {
synchronized(lock) { lock.lock()
return original.remove(key) val returnValue = original.remove(key)
} lock.unlock()
return returnValue
} }
override fun hashCode(): Int { override fun hashCode(): Int {
synchronized(lock) { lock.acquire()
return original.hashCode() val returnValue = original.hashCode()
} lock.release()
return returnValue
} }
override fun toString(): String { override fun toString(): String {
synchronized(lock) { lock.acquire()
return original.toString() val returnValue = original.toString()
} lock.release()
return returnValue
} }
override fun putIfAbsent(key: K, value: V): V? { override fun putIfAbsent(key: K, value: V): V? {
synchronized(lock) { lock.lock()
return original.putIfAbsent(key, value) val returnValue = original.putIfAbsent(key, value)
} lock.unlock()
return returnValue
} }
override fun forEach(action: BiConsumer<in K, in V>) { override fun forEach(action: BiConsumer<in K, in V>) {
synchronized(lock) { lock.acquire()
return original.forEach(action) val returnValue = original.forEach(action)
} lock.release()
return returnValue
} }
override fun getOrDefault(key: K, defaultValue: V): V { override fun getOrDefault(key: K, defaultValue: V): V {
synchronized(lock) { lock.acquire()
return original.getOrDefault(key, defaultValue) val returnValue = original.getOrDefault(key, defaultValue)
} lock.release()
return returnValue
} }
fun getOrPut(key: K, defaultValue: () -> V): V { fun getOrPut(key: K, defaultValue: () -> V): V {
synchronized(lock) { lock.lock()
var value = get(key) var value = original[key]
return if (value == null) { val returnValue = if (value == null) {
value = defaultValue() value = defaultValue()
put(key, value) original[key] = value
value value
} else { } else {
value value
} }
} lock.unlock()
return returnValue
} }
override fun remove(key: K, value: V): Boolean { override fun remove(key: K, value: V): Boolean {
synchronized(lock) { lock.lock()
return original.remove(key, value) val returnValue = original.remove(key, value)
} lock.unlock()
return returnValue
} }
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
synchronized(lock) { lock.acquire()
return original == other val returnValue = original == other
} lock.release()
return returnValue
} }
override fun replaceAll(function: BiFunction<in K, in V, out V>) { override fun replaceAll(function: BiFunction<in K, in V, out V>) {
synchronized(lock) { lock.lock()
return original.replaceAll(function) val returnValue = original.replaceAll(function)
} lock.unlock()
return returnValue
} }
override fun compute(key: K, remappingFunction: BiFunction<in K, in V?, out V?>): V? { override fun compute(key: K, remappingFunction: BiFunction<in K, in V?, out V?>): V? {
synchronized(lock) { lock.acquire()
return original.compute(key, remappingFunction) val returnValue = original.compute(key, remappingFunction)
} lock.release()
return returnValue
} }
override fun computeIfAbsent(key: K, mappingFunction: Function<in K, out V>): V { override fun computeIfAbsent(key: K, mappingFunction: Function<in K, out V>): V {
synchronized(lock) { lock.acquire()
return original.computeIfAbsent(key, mappingFunction) val returnValue = original.computeIfAbsent(key, mappingFunction)
} lock.release()
return returnValue
} }
override fun computeIfPresent(key: K, remappingFunction: BiFunction<in K, in V, out V?>): V? { override fun computeIfPresent(key: K, remappingFunction: BiFunction<in K, in V, out V?>): V? {
synchronized(lock) { lock.acquire()
return original.computeIfPresent(key, remappingFunction) val returnValue = original.computeIfPresent(key, remappingFunction)
} lock.release()
return returnValue
} }
override fun replace(key: K, value: V): V? { override fun replace(key: K, value: V): V? {
synchronized(lock) { lock.lock()
return original.replace(key, value) val returnValue = original.replace(key, value)
} lock.unlock()
return returnValue
} }
override fun merge(key: K, value: V, remappingFunction: BiFunction<in V, in V, out V?>): V? { override fun merge(key: K, value: V, remappingFunction: BiFunction<in V, in V, out V?>): V? {
synchronized(lock) { lock.lock()
return original.merge(key, value, remappingFunction) val returnValue = original.merge(key, value, remappingFunction)
} lock.unlock()
return returnValue
} }
override fun replace(key: K, oldValue: V, newValue: V): Boolean { override fun replace(key: K, oldValue: V, newValue: V): Boolean {
synchronized(lock) { lock.lock()
return original.replace(key, oldValue, newValue) val returnValue = original.replace(key, oldValue, newValue)
} lock.unlock()
return returnValue
} }
} }