2013-12-18 137 views
3

我对java.util.concurrent包中的“Semaphore”类感到困惑。这里是我的代码片段:对Semaphore类感到困惑

import java.util.concurrent.Semaphore; 

public class TestSemaphore { 
    public static void main(String[] args){ 
     Semaphore limit = new Semaphore(2); 
     SemaphoreAA s = new SemaphoreAA(limit); 
     AAThread a = new AAThread(s); 
     Thread[] sThread = new Thread[100]; 
     for(int i = 0; i<100; i++){ 
      sThread[i] = new Thread(a,"[sThread"+i+"]"); 
      sThread[i].start(); 

     } 
    } 
} 

class SemaphoreAA{ 
    private static int counter; 
    private Semaphore limit; 

    public SemaphoreAA(Semaphore limit){ 
     this.limit = limit; 
    } 

    public void increment() throws InterruptedException{ 
     System.out.printf("%-15s%-25s%5d%n",Thread.currentThread().getName()," : Before Increment. Current counter: ",counter); 
     limit.acquire(); 
     System.out.printf("%-15s%-25s%n",Thread.currentThread().getName()," : Get the resource. Start to increment."); 
     counter++; 
     System.out.printf("%-20s%-40s%5d%n",Thread.currentThread().getName()," : Increment is done. Current counter: ",counter); 
     limit.release(); 
    } 
} 

class AAThread implements Runnable{ 
    private SemaphoreAA s; 

    public AAThread(SemaphoreAA s){ 
     this.s = s; 

    } 

    public void run() { 
     try { 
      s.increment(); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
} 

我知道它可以用来控制对资源的访问。如果我将限制设置为1,就像这个“信号量限制=新的信号量(1)”,它看起来像是一个锁。它被证明。如果将限制设置为2,我预计在给定时间内有两个线程可以访问increment()方法,并且可能会导致数据竞争。输出可能是这样的:

  • [sThread3]:之前递增。当前计数器:2
  • [sThread4]:增量前。当前计数器:2
  • [sThread3]:获取资源。开始增加。
  • [sThread4]:获取资源。开始增加。
  • [sThread3]:增量完成。当前计数器:3
  • [sThread4]:递增完成。当前计数器:3

不过,虽然我已经试了好几次,并没有出现预期的结果。所以我想知道我是否误解了它。谢谢。

+0

你应该把循环放在run()方法中 - 启动线程需要时间并减少交错的可能性... – assylias

+0

它在一个线程@assylias – RamonBoza

+0

@RamonBoza每个线程只运行一条指令's.increment ()'所以启动线程的时间实际上比“增量”的时间要长得多 - 为了有机会观察交错和竞速,你需要及时调用“增量”。例如在每个线程中调用“increment”10000次。 – assylias

回答

3

你明白了吧。

但是,虽然我已经尝试了几次,但预期的结果并没有发生。

仅仅因为它可以出现并不意味着它会。这是大多数并发错误的问题:它们有时会出现,有时不会。

如果您想要增加发生错误的可能性,您可以增加Thread的数量,或者在两个不同的循环之后创建/启动它们。

+0

我得到了你,这就是为什么我已经尝试了几次,并将线程数增加到100(而不是10)来捕获预期结果。但是,它没有工作。 – franksunnn

+0

然后使用两个循环。预先创建'Thread'对象。 –

+1

@franksunn尝试在增值之前将值赋予局部变量,然后执行if(local + 1!= counter){fail();在这种情况下,你可以一遍又一遍地运行它,直到它最终失败。 –