2012-05-17 38 views
2

使用Java的Semaphore类制作的以下并发代码会根据控制台输出输入一个死锁,即使很困难,该许可证也会被释放。即使许可证被释放,信号量类是否可以进入死锁?

package ThreadTraining; 

import java.util.concurrent.Semaphore; 

public class ThreadTraining { 

    public static class Value { 

     private static int value = 0; 
     private static final Semaphore SEMAPHORE = new Semaphore(1); 

     public static synchronized void acquire() throws InterruptedException { 
      SEMAPHORE.acquire(); 
      System.out.println("A thread has aquired a permit!"); 
     } 

     public static synchronized void release() { 
      SEMAPHORE.release(); 
     } 

     public static int get() { 
      return value; 
     } 

     public static void add() { 
      value++; 
     } 

     public static void subtract() { 
      value--; 
     } 
    } 

    public static class Adder extends Thread { 

     public Adder(String name) { 
      this.setName(name); 
     } 

     @Override 
     public void run() { 
      System.out.println(this.getName() + " has been created."); 
      boolean keepRunning = true; 
      while (keepRunning) { 
       try { 
        Value.acquire(); 
        System.out.print(this.getName() + " has aquired Value's permit. --- "); 
        if (Value.get() > 99) { 
         System.out.print(this.getName() + " has finished it's job. --- "); 
         keepRunning = false; 
        } else { 
         System.out.print(this.getName() + " has modified value from " + Value.get() + " to "); 
         Value.add(); 
         System.out.println(Value.get() + "."); 
        } 
       } catch (InterruptedException ie) { 
        System.err.println("This thread was interrupted."); 
       } finally { 
        System.out.println(this.getName() + " is releasing Value's permit."); 
        Value.release(); 
       } 
      } 
     } 
    } 

    public static void main(String[] args) { 
     Thread threads[] = new Thread[3]; 
     for (int i = 0; i < threads.length; i++) { 
      threads[i] = new Adder("[Adder]Thread #" + i); 
     } 
     for (Thread t : threads) { 
      t.start(); 
     } 
    } 
} 

代码的控制台输出:(这是一个“幸运”运行,它通常只打印到指定点)

[Adder]Thread #0 has been created. 
[Adder]Thread #1 has been created. 
[Adder]Thread #2 has been created. 
A thread has aquired a permit! 
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 0 to 1. 
[Adder]Thread #0 is releasing Value's permit. /*NOTE: It usually prints only up to this line, hanging after the first permit-release.*/ 
A thread has aquired a permit! 
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 1 to 2. 
[Adder]Thread #0 is releasing Value's permit. 
A thread has aquired a permit! 
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 2 to 3. 
[Adder]Thread #0 is releasing Value's permit. 
A thread has aquired a permit! 
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 3 to 4. 
[Adder]Thread #0 is releasing Value's permit. 
A thread has aquired a permit! 
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 4 to 5. 
[Adder]Thread #0 is releasing Value's permit. 
A thread has aquired a permit! 
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 5 to 6. 
[Adder]Thread #0 is releasing Value's permit. 
A thread has aquired a permit! 
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 6 to 7. 
[Adder]Thread #0 is releasing Value's permit. 
A thread has aquired a permit! 
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 7 to 8. 
[Adder]Thread #0 is releasing Value's permit. 

什么是其背后的原因是什么?如果可能的话,如何解决它?


附加信息:

这个问题是一个的my previous concurrency question “延续”。

新代码基于this semaphore tutorial

回答

4

问题是你自己的方法的同步。无论Value.acquireValue.release是同步的,所以一个线程进入你acquire - 方法将阻止呼叫release一个又一个,因为release呼叫等待Value -class的显示器被释放,而里面acquire的人会等待内部信号量被收购。从您的方法中删除​​-keywords,您将摆脱死锁问题。相反,您可能想要同步您的get - ,add - 和subtract-方法。

+0

嗯,但不会删除aquire()方法中的\ [synchronized]创建一个多线程同时调用它的机会?我只从发布的()方法中删除,它似乎已经解决了。 – XenoRo

+0

如果多个线程同时调用您的“获取”方法并不重要,因为信号量的获取只允许获取最大数量的许可证(在您的情况1中),并且当它们用完时,其他线程将阻塞,直到获得所需的许可证数量(Semaphores获得的资源超过一次可以获得多个许可证)。既然你只允许在信号量中使用一个许可证,它的行为类似于互斥体。有关详细信息,请参阅http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Semaphore.html#acquire%28%29。 – esaj

+0

我很担心Semaphore的内部机制可能允许线程竞争场景。例如,如果第二个线程(内部)获取第一个线程已获取的许可证,则在信号量(内部)设置为允许“不再可获取”之前。我在这之前的最后一个问题提供了这种情况的一个很好的例子(它是输出中的后果)。这可能并非如此艰难。 – XenoRo

相关问题