My question is: What's the "best" way to control threading a list of many "RunnableObjects"?
I have a way that I approach multithreading, but I don't think it's optimal. There are many instances where I have a list of objects which all need to do the same thing, but I don't want them to do them one at a time, so I'll put them in a list and thread some of them at once. When one is finished, it calls an updateList() method on the controller which will remove the finished items and call new ones. I don't think this is a very good way to go about it. I'd like to use something like .notify(), but I'm not sure how it works in this context (directing me to a good site to learn may be useful).
I have a basic outline of my controller class below. I've tried to make the javadoc useful, so if you're into skimming, go ahead and just read that. Thanks.
Just some sample code to give you the idea of what I'm talking about.
package controller;
import java.util.ArrayList;
import java.util.List;
import model.RunnableObject;
public class RunnableObjectController {
private static RunnableObjectController instance;
private List<RunnableObject> runnableObjects = new ArrayList<>();
private List<RunnableObject> queuedRunnableObjects = new ArrayList<>();
private List<RunnableObject> currentRunnableObjects = new ArrayList<>();
private int limit = 10;
private RunnableObjectController() {
}
public static RunnableObjectController getInstance() {
if (instance == null) {
instance = new RunnableObjectController();
}
return instance;
}
/**
* Updates the list.
*/
public void begin() {
updateList();
}
/**
* Called by a runnableObject when it's finished with its process
*/
public synchronized void updateList() {
removeFinishedRunnableObjects();
addNewRunnableObjects();
if (isFinished()) {
MainController.getInstance().finish();
}
}
/**
* Searches the currentRunnableObjects for runnableObjects which are not in progress and removes them from the currentRunnableObjects.
* It will add them to the queuedRunnableObjects if they are of status WAITING.
*/
private void removeFinishedRunnableObjects() {
int i = 0;
while (i < currentRunnableObjects.size()) {
RunnableObject runnableObject = currentRunnableObjects.get(i);
if (runnableObject.getStatus() != RunnableObject.IN_PROGRESS) {
currentRunnableObjects.remove(runnableObject);
if (runnableObject.getStatus() == RunnableObject.WAITING) {
queuedRunnableObjects.add(runnableObject);
}
} else {
i++;
}
}
}
/**
* Searches the queuedRunnableObjects and adds them to the currentRunnableObjects while the size of the currentRunnableObjects is less than the limit.
* Begins the runnableObject in a new thread and sets its status to IN_PROGRESS
*/
private void addNewRunnableObjects() {
while (!queuedRunnableObjects.isEmpty() && currentRunnableObjects.size() < limit) {
RunnableObject runnableObject = queuedRunnableObjects.get(0);
if (runnableObject.getStatus() == RunnableObject.WAITING) {
addCurrentRemoveQueued(runnableObject);
new Thread(runnableObject).start();
runnableObject.setStatus(RunnableObject.IN_PROGRESS);
}
}
}
/**
* Adds the runnableObject to the currentThreadsObjects and removes it from the queuedRunnableObjects
*/
private synchronized void addCurrentRemoveQueued(RunnableObject runnableObject) {
currentRunnableObjects.add(runnableObject);
queuedRunnableObjects.remove(runnableObject);
}
/**
* Checks whether the current and queued notification lists are empty. Returns true if they both are.
*
* @return
*/
private boolean isFinished() {
if (queuedRunnableObjects.isEmpty() && currentRunnableObjects.isEmpty()) {
return true;
}
return false;
}
}
java.util.concurrent?java.util.concurrentI strongly suggest you do so. If you have, it would help for you to update your post explaining why that framework doesn't do what you want.java.util.concurrent, thanks for the tip, I'll look into it.