2013-01-08 118 views
3

我正在学习Java多线程,并且遇到问题,我无法理解Semaphores。我怎样才能按此顺序执行线程?例如:在image1上:第5个线程开始运行,然后1-st和2 -nd完成执行。使用信号量在Java中进行多线程编程

图片2:

enter image description here


图片1:

enter image description here

我现在上传图片以获取更好的理解。 :))

+0

如果您希望某些任务在执行N个其他任务后执行,您可以使用['CountDownLatch'](http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/CountDownLatch。 HTML)。 – Pshemo

+0

在第一个图上,线程并不是平行的,而是顺序的。每个线程等待直到其他完成,然后创建一个新线程。第二个图一次创建所有线程,但它们不同步。 –

+2

你永远不应该试图做到这一点。只需跳过并阅读实践中的并发。 – djechlin

回答

1

通常在Java中你使用互斥(也称为显示器),禁止该该代码区利用sychronized声明

定义的两个或多个线程访问由互斥

proctected代码区域

sychronized(mutex) { 
// mutual exclusive code begin 
// ... 
// ... 
// mutual exclusive code end 

} 

其中互斥定义为如:

Object mutex = new Object(); 

为了防止任务从beeing开始,你需要进阶在java.util.concurrency包中定义的诸如障碍等先进技术。

但首先让自己与​​声明一起舒适。

如果你认为你会经常使用的java多线程,则可能需要“在实践中的Java并发”改为

0

同步使用,这样每个线程将进入该方法或该部分的代码在一次。如果你想要

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(); 
    } 
    } 
} 

这是一个计数信号量的实现。它保持计数器变量的'值','等待计数'和'notifyCount'。如果值小于waitCount且notifyCount为空,则使线程等待。

您可以使用Java Counting Semaphore。从概念上讲,信号量维护一套许可证。如果需要,每个获取()都会阻止,直到获得许可证为止,然后将其获取。每个版本()都添加一个许可证,可能会释放一个阻止的收单机构。但是,没有使用实际的许可证对象;信号量只是保持可用数量的计数,并据此采取行动。

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

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实现不同),“锁定”可以由所有者之外的线程释放(因为信号量没有所有权概念)。这在一些特定的上下文中很有用,例如死锁恢复。