Java - выполнение заданий асинхронно с использованием ReentrantLock - PullRequest
6 голосов
/ 21 февраля 2011

Приведенный ниже код позволяет нам запускать job, при этом гарантируя, что одновременно может выполняться только одно задание, используя ReentrantLock.

. Есть ли способ изменить этот код для запуска job.call()асинхронно и возвращать MyConcurrentJobException клиенту до запуска потока?

Мы пытались обернуть блок try / catch / finally в новый Thread, но unlock и lock должныпроисходит в том же потоке, поэтому мы получаем 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");
    }
}

Ответы [ 2 ]

5 голосов
/ 21 февраля 2011

Вы можете использовать Semaphore вместо ReentrantLock, его разрешения не связаны с потоком.

Как-то так (не уверен, что вы хотите сделать с результатом job.call() в асинхронном режимедело):

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();
            }
        }
    });    
}
0 голосов
/ 21 февраля 2011

Я думаю, что я полностью неправильно понимаю, потому что блокировать и ждать при выполнении чего-либо асинхронно не имеет для меня особого смысла, если не будет достигнут некоторый прогресс в вызывающем потоке.

Не могли бы вы сделать что-то вроде этого:

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");
    }
}
...