Java 即使许可证被释放,信号量类也会进入死锁吗?
下面的并发代码使用Java的信号量类生成,进入死锁,甚至很难,根据控制台输出,许可证正在被释放Java 即使许可证被释放,信号量类也会进入死锁吗?,java,multithreading,concurrency,deadlock,semaphore,Java,Multithreading,Concurrency,Deadlock,Semaphore,下面的并发代码使用Java的信号量类生成,进入死锁,甚至很难,根据控制台输出,许可证正在被释放 package ThreadTraining; import java.util.concurrent.Semaphore; public class ThreadTraining { public static class Value { private static int value = 0; private static final Semaph
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();
}
}
}
背后的原因是什么?如果可能的话,如何修复它
其他信息: 这是一个“延续”的问题
新的代码非常基于。问题在于您自己的方法的同步。
Value.acquire
和Value.release
都是同步的,因此输入acquire
-方法的一个线程将阻止另一个线程调用release
,因为release
调用将等待Value
-类的监视器被释放,而acquire
中的一个将等待获取内部信号量。从方法中删除synchronized
-关键字,您将摆脱死锁问题。相反,您可能打算同步您的get
-、add
-和subtract
-方法。问题在于同步您自己的方法。Value.acquire
和Value.release
都是同步的,因此输入acquire
-方法的一个线程将阻止另一个线程调用release
,因为release
调用将等待Value
-类的监视器被释放,而acquire
中的一个将等待获取内部信号量。从方法中删除synchronized
-关键字,您将摆脱死锁问题。相反,您可能想同步get
-、add
-和subtract
-方法。Hmm,但是从aquire()方法中删除[synchronized]不会造成多个线程同时调用它的机会吗?我只从released()方法中删除了它,它似乎已经成功了。如果多个线程同时调用您的acquire
-方法,这并不重要,因为信号灯的acquire将只允许获取最大数量的许可证(在您的案例1中),当它们用完时,其他线程将阻塞,直到所需数量的许可证可用为止(信号量的获取有一个重载,您可以一次获取多个许可证)。由于在信号量中只允许一个许可证,因此它的作用类似于互斥。有关详细信息,请参阅。我担心信号量的内部机制可能会允许线程竞争场景。例如,如果第二个线程(内部)获取了第一个线程已经获取的许可,则在信号量(内部)将该许可设置为“不再可获取”之前。我在这之前的最后一个问题提供了这样一个场景的好例子(以及它在输出中的后果)。情况可能并不难。@TheLima:如果java.util.concurrent中的类本身就不是线程安全的,那么我现在就麻烦大了;)也就是说,信号量是为了线程同步而构建的。如果信号量本身有一个内部竞争条件,那么Java.Hmm的标准库中确实存在严重错误,但是从aquire()方法中删除[synchronized]会不会造成多个线程同时调用它的可能性?我只从released()方法中删除了它,它似乎已经成功了。如果多个线程同时调用您的acquire
-方法,这并不重要,因为信号灯的acquire将只允许获取最大数量的许可证(在您的案例1中),当它们用完时,其他线程将阻塞,直到所需数量的许可证可用为止(信号量的获取有一个重载,您可以一次获取多个许可证)。由于在信号量中只允许一个许可证,因此它的作用类似于互斥。有关详细信息,请参阅。我担心信号量的内部机制可能会允许线程竞争场景。例如,如果第二个线程(内部)获取了第一个线程已经获取的许可,则在信号量(内部)将该许可设置为“不再可获取”之前。我在这之前的最后一个问题提供了这样一个场景的好例子(以及它在输出中的后果)。情况可能并不难。@TheLima:如果java.util.concurrent中的类本身就不是线程安全的,那么我现在就麻烦大了;)也就是说,信号量是为了线程同步而构建的。如果一个信号量本身有一个内部竞争条件,那么在Java的标准库中确实存在严重错误。
[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.