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。
嗯,但不会删除aquire()方法中的\ [synchronized]创建一个多线程同时调用它的机会?我只从发布的()方法中删除,它似乎已经解决了。 – XenoRo
如果多个线程同时调用您的“获取”方法并不重要,因为信号量的获取只允许获取最大数量的许可证(在您的情况1中),并且当它们用完时,其他线程将阻塞,直到获得所需的许可证数量(Semaphores获得的资源超过一次可以获得多个许可证)。既然你只允许在信号量中使用一个许可证,它的行为类似于互斥体。有关详细信息,请参阅http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Semaphore.html#acquire%28%29。 – esaj
我很担心Semaphore的内部机制可能允许线程竞争场景。例如,如果第二个线程(内部)获取第一个线程已获取的许可证,则在信号量(内部)设置为允许“不再可获取”之前。我在这之前的最后一个问题提供了这种情况的一个很好的例子(它是输出中的后果)。这可能并非如此艰难。 – XenoRo