I've designed this small application. I want to know if there are some chances of race conditions, deadlocks or memory leaks in it. Please give your comments.
The problem is that I need to do some task that takes about 3 minutes to complete. The same task can be submitted by multiple clients. So while a task is running, if another request comes for processing the same task again, I don't want to do it again, and I want to use the results produced by already running task.
Here are the classes involved:
Expand|Select|Wrap|Line Numbers
- /*
- *This class accepts the queries from the client
- */
- public class Processor {
- public List<Details> processQuery(Query query) throws ProcessorException {
- QueryResult result = requestCache.getResult(query);
- synchronized (result) {
- while (!result.isCompleted() && result.isClean()) {
- // task is being processed, so wait
- try {
- result.wait();
- } catch (InterruptedException e) {
- //TODO:
- }
- }
- }
- // wait over
- if (result.isClean() && result.isCompleted()) {
- return result.getList();
- }
- // task was not processed successfully
- throw new ProcessorException();
- }
- }
- /*
- *This is the result class whose objects will hold results of the processed tasks
- */
- public class QueryResult {
- private volatile boolean completed = false;
- private volatile boolean clean = true;
- private List<Details> list;
- public List<Details> getList() {
- return list;
- }
- public synchronized void setList(List<Details> list) {
- this.list = list;
- this.completed = true;
- // notify all threads waiting for the results
- notifyAll();
- }
- public boolean isCompleted() {
- return completed;
- }
- public boolean isClean() {
- return clean;
- }
- // something has gone wrong, set isClean flag and notify all waiting threads
- public synchronized void corrupt() {
- this.clean = false;
- notifyAll();
- }
- }
- /*
- *This class does the actual processing and maintains the list of tasks being processed
- */
- public class RequestCache {
- private final ConcurrentHashMap<Query, QueryResult> results = new ConcurrentHashMap<Query, QueryResult>();
- public QueryResult getResult(Query query) {
- QueryResult result = results.get(query);
- if (result != null) {
- // query is already under processing
- return result;
- }
- result = new QueryResult();
- QueryResult previousResult = results.putIfAbsent(query, result);
- if (previousResult != null) {
- // some other thread already submitted the query for processing
- return previousResult;
- }
- // now we need to process the query ourself
- try {
- List<Details> list = doProcessing(query); // this takes about 3 minutes
- // this will set the list as well as notify all threads waiting for this result
- result.setList(list);
- } catch (Exception e) {
- // an exception occured, so we should notify everybody of the error
- // remove the query from the map, so that new requests does not get the corrupt response
- results.remove(query);
- result.corrupt();
- synchronized (result) {
- result.notifyAll();
- }
- }
- results.remove(query);
- return result;
- }
- }