Fix: synchronize method bodies instead of completely relying on synchronized colelctions

Should prevent ConcurrentModificationExceptions and runtime corruption
This commit is contained in:
artdeell 2023-01-30 22:58:19 +03:00
parent 3004503b84
commit 246bf5c1dc

View File

@ -1,19 +1,15 @@
package net.kdt.pojavlaunch.progresskeeper;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
public class ProgressKeeper {
private static final ConcurrentHashMap<String, ConcurrentLinkedQueue<ProgressListener>> sProgressListeners = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<String, ProgressState> sProgressStates = new ConcurrentHashMap<>();
private static final List<TaskCountListener> sTaskCountListeners = Collections.synchronizedList(new ArrayList<>());
private static final HashMap<String, List<ProgressListener>> sProgressListeners = new HashMap<>();
private static final HashMap<String, ProgressState> sProgressStates = new HashMap<>();
private static final List<TaskCountListener> sTaskCountListeners = new ArrayList<>();
public static void submitProgress(String progressRecord, int progress, int resid, Object... va) {
public static synchronized void submitProgress(String progressRecord, int progress, int resid, Object... va) {
ProgressState progressState = sProgressStates.get(progressRecord);
boolean shouldCallStarted = progressState == null;
boolean shouldCallEnded = resid == -1 && progress == -1;
@ -31,7 +27,7 @@ public class ProgressKeeper {
progressState.varArg = va;
}
ConcurrentLinkedQueue<ProgressListener> progressListeners = sProgressListeners.get(progressRecord);
List<ProgressListener> progressListeners = sProgressListeners.get(progressRecord);
if(progressListeners != null)
for(ProgressListener listener : progressListeners) {
if(shouldCallStarted) listener.onProgressStarted();
@ -40,14 +36,14 @@ public class ProgressKeeper {
}
}
private static void updateTaskCount() {
private static synchronized void updateTaskCount() {
int count = sProgressStates.size();
for(TaskCountListener listener : sTaskCountListeners) {
listener.onUpdateTaskCount(count);
}
}
public static void addListener(String progressRecord, ProgressListener listener) {
public static synchronized void addListener(String progressRecord, ProgressListener listener) {
ProgressState state = sProgressStates.get(progressRecord);
if(state != null && (state.resid != -1 || state.progress != -1)) {
listener.onProgressStarted();
@ -55,32 +51,32 @@ public class ProgressKeeper {
}else{
listener.onProgressEnded();
}
ConcurrentLinkedQueue<ProgressListener> listenerWeakReferenceList = sProgressListeners.get(progressRecord);
if(listenerWeakReferenceList == null) sProgressListeners.put(progressRecord, (listenerWeakReferenceList = new ConcurrentLinkedQueue<>()));
List<ProgressListener> listenerWeakReferenceList = sProgressListeners.get(progressRecord);
if(listenerWeakReferenceList == null) sProgressListeners.put(progressRecord, (listenerWeakReferenceList = new ArrayList<>()));
listenerWeakReferenceList.add(listener);
}
public static void removeListener(String progressRecord, ProgressListener listener) {
ConcurrentLinkedQueue<ProgressListener> listenerWeakReferenceList = sProgressListeners.get(progressRecord);
public static synchronized void removeListener(String progressRecord, ProgressListener listener) {
List<ProgressListener> listenerWeakReferenceList = sProgressListeners.get(progressRecord);
if(listenerWeakReferenceList != null) listenerWeakReferenceList.remove(listener);
}
public static void addTaskCountListener(TaskCountListener listener) {
public static synchronized void addTaskCountListener(TaskCountListener listener) {
listener.onUpdateTaskCount(sProgressStates.size());
if(!sTaskCountListeners.contains(listener)) sTaskCountListeners.add(listener);
}
public static void addTaskCountListener(TaskCountListener listener, boolean runUpdate) {
public static synchronized void addTaskCountListener(TaskCountListener listener, boolean runUpdate) {
if(runUpdate) listener.onUpdateTaskCount(sProgressStates.size());
if(!sTaskCountListeners.contains(listener)) sTaskCountListeners.add(listener);
}
public static void removeTaskCountListener(TaskCountListener listener) {
public static synchronized void removeTaskCountListener(TaskCountListener listener) {
sTaskCountListeners.remove(listener);
}
/**
* Waits until all tasks are done and runs the runnable, or if there were no pending process remaining
* The runnable runs from the thread that updated the task count last, and it might be the UI thread,
* so dont put long running processes in it
* so don't put long running processes in it
* @param runnable the runnable to run when no tasks are remaining
*/
public static void waitUntilDone(final Runnable runnable) {
@ -101,7 +97,7 @@ public class ProgressKeeper {
addTaskCountListener(listener);
}
public static int getTaskCount() {
public static synchronized int getTaskCount() {
return sProgressStates.size();
}
}