【问题标题】:Is there a way to include a Condition to adquire method in java (or scala) Semaphore object?有没有办法在java(或scala)信号量对象中​​包含一个条件来获取方法?
【发布时间】:2012-06-23 03:53:32
【问题描述】:

我有一个包含许多线程的程序,让我们以六个线程为例。其中五个应该能够同时使用给定资源,但如果给定条件发生,最后一个线程不应该,并且应该等到该条件结束。

据我了解,不能使用 ReentrantLock,因为它一次只能由一个线程持有。另一方面,信号量可以同时被多个线程持有,但我找不到将条件附加到获取方法的方法。

这个高级对象能否解决问题,或者我将不得不使用通知来实现这个功能并直接等待?

例如。

class A{
   getResource{ ... }
}

//This Runable could be spawn many times at the same time
class B implements Runnable{
   run {
      setConditionToTrue
      getResource
      ...
      getResource
      ...
      getResource
      setConditionToFalse
   }
}

//This will be working forever but only one Thread
class C implements Runnable{
   run{
      loop{
         if(Condition == true) wait
         getResource
      }
   }
}

提前感谢各位朋友

【问题讨论】:

    标签: java scala locking semaphore synchronizing


    【解决方案1】:

    我在这里重申您的问题:您希望您的 B 线程同时访问共享资源,但您的 C 线程应该等待某些条件发生后才能使用该资源。

    如果我正确理解您的问题,您可以使用ReentrantLock 来解决您的问题。

    引入一个新的函数getAccess(),让C线程调用这个函数来获取共享资源。引入另外两个函数来允许和停止对共享资源的访问。

    class A {
    
      private final ReentrantLock lock = new ReentrantLock();
      private Condition someCondition = lock.newCondition();
      private boolean bCondition = false;
    
      getResource{ ... } // Your existing method used by B threads
    
      getAccess() { // Protected access to some resource, called by C thread
        lock.acquire();
    
        try {
          if (!bCondition)
            someCondition.await(); // B thread will wait here but releases the lock
        } finally {
          lock.release();
        }
      }
    
      allowAccess() { // B thread can call this func to notify C and allow access
        lock.acquire();
        try {
          bCondition = true;
          someCondition.signal(); // Decided to release the resource
        } finally {
          lock.release();
        }
      }
    
      stopAccess() { // B thread can stop the access
        lock.acquire();
        try {
          bCondition = false;
        } finally {
          lock.release();
        }
      }
    
    }
    

    【讨论】:

    • 如果线程 B#1 调用 stopAccess() 并开始做他的工作,在它结束之前 B#2 再次调用 stopAccess() B#2 会被阻止吗?如果是这种情况,这将行不通,因为我需要同时运行大量 B 而不锁定。
    • B#1 调用 stopAccess(),翻转布尔值并立即释放锁,因此 B#2 或任何其他线程调用 stopAccess() 并且它们不会被阻塞。
    • 是的,你完全正确。这将起作用。谢谢你,sperumal
    【解决方案2】:

    如果您希望多个线程共享一个资源,您需要更具体地了解该共享的含义。通常这意味着区分那些读取资源当前值的线程和改变该值的其他线程。如果写入是无竞争且稳定的,这意味着是并发读取/独占写入模式(“船员”)。

    在 Java API 中,这是由 ReentrantReadWriteLock 提供的。还有其他值得考虑的替代方案,例如 JCSP 中精心实现的Crew

    使用 [J]CSP,还可以使用不同的模式:将公共资源包装在自己的线程中,并通过所有客户端线程的共享 JCSP 通道提供对它的访问。鉴于线程通信图是非循环的 (more),这种客户端-服务器模式易于理解和实现,并且具有形式上无死锁的额外好处。

    【讨论】:

    • 谢谢瑞克,是的,就像你提到的那样,我需要的是写权限。我想继续使用核心库来解决这个问题,所以我会坚持使用 sperumal 解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 2017-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多