java 强制获取锁?

java forcing acquire of lock?

我正在使用有点过时的工作流引擎,它允许定义执行 Java 代码的单个步骤,但不能超过这个。

工作流流程的每次调用都在其自己的线程中运行,任何子流程在同一线程中同步执行。

工作流引擎不允许捕获流程中发生的所有异常。我需要让一些子进程单线程运行,即等待另一个线程正在执行子进程。

到目前为止我能想到的就是在子进程的第一步获取锁,并在结束步骤释放它。如果过程中出现异常,并不总是能够捕捉到它。

... s_lock = new ReentrantLock(); ...
... s_timeout = 10; ...

public static void acquireLock() throws InterruptedException {
    if( !s_lock.tryLock(s_timeout, TimeUnit.SECONDS)) {
        System.out.println("WARN: Forcing acquire of lock.");
        s_lock = new ReentrantLock();   // discard old lock and create a new one
        s_lock.lock();
    }
}

public static void releaseLock() {
    if( s_lock.isHeldByCurrentThread()) {
        s_lock.unlock();
    } else {
        System.out.println("WARN:  lock not held by thread.");          
    }
}

一定有更好的办法吧?是否可以在线程终止时自动释放锁?

Is it possible to automatically release the lock if a thread terminates?

不适用于任何标准 Lock 实现。 AFAIK,它们都有这样的限制,即只有获得锁的线程才能释放它。因此,在您的每个工作流进程都在不同线程中的用例中,后面的工作流进程无法打破在较早的进程失败时放弃的锁。

但并非一无所有。 Lock.unlock() 的 javadoc 是这样说的:

Implementation Considerations

A Lock implementation will usually impose restrictions on which thread can release a lock (typically only the holder of the lock can release it) and may throw an (unchecked) exception if the restriction is violated. Any restrictions and the exception type must be documented by that Lock implementation.

请注意,该限制不是强制性的。因此,您可以 编写自己的 Lock 实现,而不受 unlock().

的限制

另外,如果能保证运行工作流进程的线程不被重用,有一种方案可以安全破锁。

  • 当一个线程获取其中一个锁时,它会将一个由当前 Thread 对象和锁组成的元组传递给一个单独的锁监视器线程。

  • 锁监视器线程定期扫描元组以查找所有未完成的锁。

  • 对于每个元组,监视器调用Thread.isAlive()来测试持有锁的线程是否仍然是运行ning。当一个带锁的线程不再运行ning时,监控线程解锁锁,并丢弃元组。

不幸的是,这需要进行轮询,但您应该能够实现这一点,以便监控线程仅在锁处于获取状态时进行轮询。


实施自定义 Lock class 和锁监视器并非易事...


顺便说一下,您当前的方法存在缺陷:

  • 如果超时时间小,在原来的workflow进程还在运行ning的时候,有可能会破坏锁。

  • 如果超时时间较长,则失败的工作流过程可能会阻塞其他工作流过程太长时间。

  • 没有“中途”点可以保证可靠的锁定和响应。