Question

The code below allows us to run a job while ensuring that only one job at a time can run by using ReentrantLock.

Is there any way to modify this code to run job.call() asynchronously and to return the MyConcurrentJobException to the client prior to starting the thread?

We tried wrapping the try/catch/finally block in a new Thread but the unlock and lock have to happen in the same thread so we get an IllegalMonitorException

??

final static Lock lock = new ReentrantLock();

public Object runJob(String desc, Callable job, boolean wait) {
    logger.info("Acquiring lock");
    if (!lock.tryLock()) {
        throw new MyConcurrentJobException();
    }

    activeJob = new JobStatus(desc);
    logger.info("Lock acquired");

    try {
        return job.call();
    } catch (MarginServiceAssertionException e) {
        throw e;
    } catch (MarginServiceSystemException e) {
        throw e;
    } catch (Exception e) {
        throw new MarginServiceSystemException(e);
    } finally {
        activeJob = null;
        logger.info("Releasing lock");
        lock.unlock();
        logger.info("Lock released");
    }
}
Was it helpful?

Solution

You can use Semaphore instead of ReentrantLock, its permits are not bound to thread.

Something like this (not sure what you want to do with the result of job.call() in the asynchronous case):

final static Semaphore lock = new Semaphore(1);

public void runJob(String desc, Callable job, boolean wait) {
    logger.info("Acquiring lock");
    if (!lock.tryAcquire()) {
        throw new MyConcurrentJobException();
    }

    startThread(new Runnable() {
        public void run() {
            try {
                job.call();
            } finally {
                lock.release();
            }
        }
    });    
}

OTHER TIPS

I think I am misunderstanding completely because to block and wait while doing something asynchronously doesn't make too much sense to me unless some progress can be made on the invoking thread.

Could you do something like this:

final static Lock lock = new ReentrantLock();
final static ExecutorService service = Executors.newThreadPoolExecutor();
public Object runJob(String desc, Callable job, boolean wait) {
    logger.info("Acquiring lock");
    if (!lock.tryLock()) {
        throw new MyConcurrentJobException();
    }

    activeJob = new JobStatus(desc);
    logger.info("Lock acquired");

    try {
        Future<?> future = service.submit(job);
        // This next line will block until the job is finished
        // and also will hold onto the lock.
        boolean finished = false;
        Object o = null;
        while(!finished) {
            try {
                o = future.get(300, TimeUnit.MILLISECONDS);
                finished = true;
            catch(TimeOutException e) {
                // Do some periodic task while waiting
                // foot.tapLots();
            }
         }
         if (o instanceof MarginServiceAssertionException) {
             throw ((MargineServiceAssertionException)o);
         } else if (o instanceof MargineServiceSystemException) {
             throw ((MarginServiceSystemException)o);
         } else if (o instanceof Exception) {
             throw new MarginServiceSystemException(e);
         }
    } catch (... InterruptedException e) { /// catch whatever exceptions throws as part of this
       /// Whatever needs to be done.
    } finally {
        activeJob = null;
        logger.info("Releasing lock");
        lock.unlock();
        logger.info("Lock released");
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top