使用信号量在Java中进行多线程编程

时间:2013-01-08 21:02:59

标签: java multithreading semaphore wait notify

我正在学习Java多线程,我有问题,我无法理解信号量。如何按此顺序执行线程?例如:on image1:第5个线程开始运行,然后1-st和2-nd完成执行。

图片2:

enter image description here


图片1:

enter image description here

我现在上传图片以便更好地理解。 :))

2 个答案:

答案 0 :(得分:1)

通常在java中使用互斥锁(也称为监视器),它禁止两个或多个线程访问该互斥锁检测到的代码区域

使用sychronized语句

定义该代码区域
sychronized(mutex) {
 // mutual exclusive code begin
 // ...
 // ...
 // mutual exclusive code end

}

其中互斥定义为例如:

Object mutex = new Object();

为防止任务启动,您需要在java.util.concurrency包中定义的高级技术,例如障碍。

但首先要让自己对synchronized陈述感到轻松。

如果您认为在java中经常使用多线程,则可能需要阅读

“Java Concurrency in Practice”

答案 1 :(得分:0)

使用Synchronized,以便每个线程一次输入该方法或代码的那部分。如果你想

public class CountingSemaphore {
  private int value = 0;
  private int waitCount = 0;
  private int notifyCount = 0;

  public CountingSemaphore(int initial) {
    if (initial > 0) {
      value = initial;
    }
  }

  public synchronized void waitForNotify() {
    if (value <= waitCount) {
      waitCount++;
      try {
        do {
          wait();
        } while (notifyCount == 0);
      } catch (InterruptedException e) {
        notify();
      } finally {
        waitCount--;
      }
      notifyCount--;
    }
    value--;
  }

  public synchronized void notifyToWakeup() {
    value++;
    if (waitCount > notifyCount) {
      notifyCount++;
      notify();
    }
  }
}

这是计数信号量的实现。它维护计数器变量'value','waitCount'和'notifyCount'。如果value小于waitCount并且notifyCount为空,则使线程等待。

您可以使用Java Counting Semaphore。从概念上讲,信号量保持一组许可。如果需要,每个acquire()都会阻止,直到有许可证可用,然后接受它。每个版本()都会添加一个许可证,可能会释放一个阻塞收单器。但是,没有使用实际的许可对象;信号量只是保留可用数量并相应地采取行动。

信号量通常用于限制线程数,而不是访问某些(物理或逻辑)资源。例如,这是一个使用信号量来控制对项池的访问的类:

 class Pool {
   private static final MAX_AVAILABLE = 100;
   private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);

   public Object getItem() throws InterruptedException {
     available.acquire();
     return getNextAvailableItem();
   }

   public void putItem(Object x) {
     if (markAsUnused(x))
       available.release();
   }

   // Not a particularly efficient data structure; just for demo

   protected Object[] items = ... whatever kinds of items being managed
   protected boolean[] used = new boolean[MAX_AVAILABLE];

   protected synchronized Object getNextAvailableItem() {
     for (int i = 0; i < MAX_AVAILABLE; ++i) {
       if (!used[i]) {
          used[i] = true;
          return items[i];
       }
     }
     return null; // not reached
   }

   protected synchronized boolean markAsUnused(Object item) {
     for (int i = 0; i < MAX_AVAILABLE; ++i) {
       if (item == items[i]) {
          if (used[i]) {
            used[i] = false;
            return true;
          } else
            return false;
       }
     }
     return false;
   }

 }

在获取项目之前,每个线程必须从信号量获取许可证,以保证项目可供使用。当线程完成项目后,它将返回到池中,并且许可证将返回到信号量,允许另一个线程获取该项目。请注意,调用acquire()时不会保持同步锁定,因为这会阻止项目返回到池中。信号量封装了限制访问池所需的同步,与保持池本身一致性所需的任何同步分开。

信号量初始化为1,并且使用的信号量最多只有一个许可证可用作互斥锁。这通常称为二进制信号量,因为它只有两种状态:一种是可用的,或者是零可用的。当以这种方式使用时,二进制信号量具有属性(与许多Lock实现不同),“锁”可以由除所有者之外的线程释放(因为信号量没有所有权的概念)。这在某些特定的上下文中很有用,例如死锁恢复。