Java读写锁定要求,具有来自不同线程的锁定和释放

我试图找到一个不那么笨重的Java并发问题的解决方案.

问题的关键在于,当仍有工作线程处于活动状态时,我需要对块进行关闭调用,但关键的方面是每个工作任务都是异步生成和完成的,因此保持和释放必须由不同的线程完成.一旦他们的工作完成,我需要他们以某种方式向关闭线程发送信号.只是为了让事情更有趣,工作线程不能互相阻塞,所以我不确定信号量在这个特定实例中的应用.

我有一个解决方案,我认为安全地完成了这项工作,但是我对Java并发工具的不熟悉使我认为可能有一个更简单或更优雅的模式.在这方面的任何帮助将不胜感激.

这是我到目前为止,除了评论之外相当稀疏:

final private ReentrantReadWriteLock shutdownLock = new ReentrantReadWriteLock();
volatile private int activeWorkerThreads;
private boolean isShutdown;

private void workerTask()
{
   try
   {
      // Point A: Worker tasks mustn't block each other.
      shutdownLock.readLock().lock();

      // Point B: I only want worker tasks to continue if the shutdown signal
      // hasn't already been received.
      if (isShutdown)
         return;

      activeWorkerThreads ++;

      // Point C: This async method call returns immediately, soon after which
      // we release our lock. The shutdown thread may then acquire the write lock
      // but we want it to continue blocking until all of the asynchronous tasks
      // have completed.
      executeAsynchronously(new Runnable()
      {
         @Override
         final public void run()
         {
            try
            {
              // Do stuff.
            }
            finally
            {
               // Point D: Release of shutdown thread loop, if there are no other
               // active worker tasks.
               activeWorkerThreads --;
            }
         }
      });
   }
   finally
   {
      shutdownLock.readLock().unlock();
   }
}


final public void shutdown()
{
   try
   {
      // Point E: Shutdown thread must block while any worker threads
      // have breached Point A.
      shutdownLock.writeLock().lock();

      isShutdown = true;

      // Point F: Is there a better way to wait for this signal?
      while (activeWorkerThreads > 0)
         ;

      // Do shutdown operation.
   }
   finally
   {
      shutdownLock.writeLock().unlock();
   }
}

在此先感谢您的帮助!

拉斯

最佳答案
您可以在此方案中使用信号量,而不需要忙等待shutdown()调用.想到它的方法是作为一套门票发给工人,表明他们在飞行中.如果shutdown()方法可以获取所有票证,那么它知道它已经耗尽了所有工作人员并且没有活动.因为#acquire()是一个阻塞调用,所以shutdown()不会旋转.我已经将这种方法用于分布式主工作库,并且可以轻松扩展它以处理超时和重试.

Executor executor = // ...
final int permits = // ...
final Semaphore semaphore = new Semaphore(permits);

void schedule(final Runnable task) {
  semaphore.acquire();
  try {
    executor.execute(new Runnable() {
      @Override public run() {
        try {
          task.run();
        } finally {
          semaphore.release();
        }
      }
    });
  } catch (RejectedExecutionException e) {
    semaphore.release();
    throw e;
  }
}

void shutDown() {
  semaphore.acquireUninterruptibly(permits);

  // do stuff
}

转载注明原文:Java读写锁定要求,具有来自不同线程的锁定和释放 - 代码日志