Java - running jobs async using ReentrantLock?
Asked Answered
A

2

6

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");
    }
}
Andrey answered 21/2, 2011 at 17:28 Comment(0)
M
5

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();
            }
        }
    });    
}
Madeup answered 21/2, 2011 at 17:33 Comment(0)
B
0

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");
    }
}
Buck answered 21/2, 2011 at 17:53 Comment(2)
We want to kick off a job using a gui.. we want to return control to the gui right away with a "your job has started" message.. but we want to prevent concurrent jobs from occurring. So if user tries to start a job while another job is underway they get an error.Andrey
ah ok, so yeah I would go with axtavt's solution then.Buck

© 2022 - 2024 — McMap. All rights reserved.