我之所以写这个问题,是因为我们在一个qa环境中遇到了一种情况,即信号量似乎失败了。 我们只有一个信号量:
private Semaphore lock = new Semaphore(1);
碰巧一个线程(Quartz作业)正在运行并持有所获取的锁,然后又触发了另一个作业并使其进入执行中间。
这两个作业都需要获取并释放锁,因此,如果第一个作业被延迟,则后者必须等待第一个作业释放锁。
奇怪的是,后者没有等待,它只是通过了lock.acquire()
场景完全不复杂,并且代码从一开始就一直在起作用。到目前为止,我们还无法重新创建它。可能是小故障?
我想知道是否有人知道Quartz和Java信号量之间是否存在某种已知的不兼容性,或者在某些情况下Java信号量是否会失败
编辑 还有一个细节,它是一个基于Deltaspike CDI框架构建的应用程序
这是用于处理锁的Singleton:
import java.util.concurrent.Semaphore;
public class Lock {
private Lock() {}
private static class SingletonHolder {
public static final Lock INSTANCE = new Lock();
}
/**
* Use this method to get a reference to the singleton instance of
* {@link Lock}
*
* @return the singleton instance
*/
public static Lock getInstance() {
return SingletonHolder.INSTANCE;
}
/**
* we allow only one thread at at time
*/
private Semaphore lock = new Semaphore(1);
public void getLock() throws InterruptedException {
lock.acquire();
}
public void releaseLock() {
lock.release();
}
}
这是第一份工作:
@Scheduled(cronExpression = "{cronExp1}")
public class Job1 implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
method1();
}
public void method1(){
long threadId = Thread.currentThread().getId();
try{
logger.debug("Thread # " + threadId + "Requesting lock...");
Lock.getInstance().getLock();
logger.debug("Thread # " + threadId + "Lock acquired.");
//...some logic
}catch (PersistenceException e) {
//.. handling exception
}catch (Exception e) {
//.. handling exception
}finally {
Lock.getInstance().releaseLock();
logger.debug("Thread # " + threadId + "Lock released.");
}
}
}
这是第二项工作:
@Scheduled(cronExpression = "{cronExp2}")
public class Job2 implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
long threadId = Thread.currentThread().getId();
try{
logger.debug("Thread # " + threadId + "Requesting lock...");
Lock.getInstance().getLock();
logger.debug("Thread # " + threadId + "Lock acquired.");
//...some logic
}catch (PersistenceException e) {
//.. handling exception
}catch (Exception e) {
//.. handling exception
}finally {
Lock.getInstance().releaseLock();
logger.debug("Thread # " + threadId + "Lock released.");
}
}
}
如您所见,作业之间的唯一区别(逻辑除外)是,作业1进入method1内部的关键区域,而Job2进入execute方法内部。