使用信号量的死锁
deadlock using Semaphore
我有一个关于管理线程的简单问题。我有 3 个进程共享同一个信号量和一个许可。在正常情况下,第一个进程获取此许可并释放两个许可至第二个进程。第二个进程发布 3 允许第三个进程。我举个例子来说明我的问题。
第一个:
public class Process0 extends Thread{
Semaphore s;
public Process0(Semaphore s){
this.s = s;
}
public void run(){
try {
sleep(20000);
s.acquire();
System.out.println("hello");
} catch (InterruptedException ex) {
Logger.getLogger(Process.class.getName()).log(Level.SEVERE, null, ex);
}
s.release(2);
}
}
第二个过程:
public class Process1 extends Thread{
Semaphore s;
public Process1(Semaphore s){
this.s = s;
}
public void run(){
try {
this.sleep(10000);
s.acquire(2);
System.out.println("Hello 2");
} catch (InterruptedException ex) {
Logger.getLogger(Process1.class.getName()).log(Level.SEVERE, null, ex);
}
s.release(3);
}
}
最后一个:
public class Process2 extends Thread{
Semaphore s;
public Process2(Semaphore s){
this.s = s;
}
public void run(){
try {
System.out.println("Acquire process 3 ");
s.acquire(3);
System.out.println("Hello 3");
} catch (InterruptedException ex) {
Logger.getLogger(Process2.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
问题是。当我 运行 这三个进程时,请确保进程 3 是第一个执行 acquire
的进程。我会陷入僵局。进程 2 从不打印 "Hello 3",进程 1 从不打印 "Hello 2"。为什么?
信号量 s = 新信号量(1);
Process0 p = new Process0(s);
Process1 p1 = new Process1(s);
Process2 p2 = new Process2(s);
p.start();
p1.start();
p2.start();
您的 Semaphore 构造为 new Semaphore(1)
,它只能获得一个许可。调用 s.acquire(3)
永远不会 return 因为信号量永远不会有三个可用的许可。 Process
尝试获取单个许可证的尝试也被阻止,因为已订购并且 Process2
已到达 "first":
release
方法 javadoc 声明在
时可以发生获取
Some other thread invokes the release() method for this semaphore and the current thread is next to be assigned a permit.
这个最小的单线程示例将向您展示:
Semaphore s = new Semaphore(1);
s.acquire(2);
System.out.println("Didn't deadlock!");
解决方法是使用 Semaphore.acquire()
请求一个许可,或者 Semaphore.acquire(1)
也只请求一个许可。
您还需要确保获得和释放相同数量的许可,除非您有非常 滥用 Semaphore
的充分理由。来自 Javadoc:
There is no requirement that a thread that releases a permit must have acquired that permit by calling acquire [or that a thread releases all of its permits]. Correct usage of a semaphore is established by programming convention in the application.
此外,您似乎为此任务使用了错误的同步器。您可以使用 CyclicBarrier
或其他 class usable for synchronization.
我花了一些时间才弄清楚你想要完成什么。这是我想出的。希望对你有帮助。
问题是您的实现中的线程试图按某种顺序获取锁。所以等待 3 个许可的线程首先等待,然后是等待 2 个许可的线程,显然排队等待他的 2 个许可,然后是第一个只想要 1 个许可的线程。有一个可用的许可证,所以很高兴。然后它 returns 2 许可。不幸的是,接下来是等待 3 个许可的线程,而不是等待 2 个许可的线程。真可惜。阻止。这就是你观察到的。
如果你让其他线程改变队列获取的位置,一切都会好起来的。来了
s.tryAcquire(int permits)
然后突然一切正常。
我会根据你的代码做一个例子,在繁忙的等待循环中休眠 1 秒,看看发生了什么。
import java.util.concurrent.Semaphore;
class Process0 extends Thread {
Semaphore s;
public Process0(Semaphore s){
this.s = s;
}
public void run(){
try {
sleep(20000);
s.acquire();
System.out.println("hello");
} catch (InterruptedException ex) {
System.out.println(Process.class.getName());
}
s.release(2);
System.out.println("released 2");
}
}
class Process1 extends Thread{
Semaphore s;
public Process1(Semaphore s){
this.s = s;
}
public void run(){
try {
this.sleep(10000);
while(!s.tryAcquire(2)) {
System.out.println("Busy waiting for 2 permits");
sleep(1000);
}
System.out.println("Hello 2");
} catch (InterruptedException ex) {
System.out.println(Process.class.getName());
}
s.release(3);
System.out.println("Released 3");
}
}
class Process2 extends Thread{
Semaphore s;
public Process2(Semaphore s){
this.s = s;
}
public void run() {
System.out.println("Acquire process 3 ");
while(!s.tryAcquire(3)) {
System.out.println("Busy waiting for 3 permits");
try {
sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Hello 3");
}
}
public class DaemonTest {
public static void main(String[] args) {
Semaphore s = new Semaphore(1);
Process0 p = new Process0(s);
Process1 p1 = new Process1(s);
Process2 p2 = new Process2(s);
p.start();
p1.start();
p2.start();
}
}
我有一个关于管理线程的简单问题。我有 3 个进程共享同一个信号量和一个许可。在正常情况下,第一个进程获取此许可并释放两个许可至第二个进程。第二个进程发布 3 允许第三个进程。我举个例子来说明我的问题。
第一个:
public class Process0 extends Thread{
Semaphore s;
public Process0(Semaphore s){
this.s = s;
}
public void run(){
try {
sleep(20000);
s.acquire();
System.out.println("hello");
} catch (InterruptedException ex) {
Logger.getLogger(Process.class.getName()).log(Level.SEVERE, null, ex);
}
s.release(2);
}
}
第二个过程:
public class Process1 extends Thread{
Semaphore s;
public Process1(Semaphore s){
this.s = s;
}
public void run(){
try {
this.sleep(10000);
s.acquire(2);
System.out.println("Hello 2");
} catch (InterruptedException ex) {
Logger.getLogger(Process1.class.getName()).log(Level.SEVERE, null, ex);
}
s.release(3);
}
}
最后一个:
public class Process2 extends Thread{
Semaphore s;
public Process2(Semaphore s){
this.s = s;
}
public void run(){
try {
System.out.println("Acquire process 3 ");
s.acquire(3);
System.out.println("Hello 3");
} catch (InterruptedException ex) {
Logger.getLogger(Process2.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
问题是。当我 运行 这三个进程时,请确保进程 3 是第一个执行 acquire
的进程。我会陷入僵局。进程 2 从不打印 "Hello 3",进程 1 从不打印 "Hello 2"。为什么?
信号量 s = 新信号量(1);
Process0 p = new Process0(s);
Process1 p1 = new Process1(s);
Process2 p2 = new Process2(s);
p.start();
p1.start();
p2.start();
您的 Semaphore 构造为 new Semaphore(1)
,它只能获得一个许可。调用 s.acquire(3)
永远不会 return 因为信号量永远不会有三个可用的许可。 Process
尝试获取单个许可证的尝试也被阻止,因为已订购并且 Process2
已到达 "first":
release
方法 javadoc 声明在
Some other thread invokes the release() method for this semaphore and the current thread is next to be assigned a permit.
这个最小的单线程示例将向您展示:
Semaphore s = new Semaphore(1);
s.acquire(2);
System.out.println("Didn't deadlock!");
解决方法是使用 Semaphore.acquire()
请求一个许可,或者 Semaphore.acquire(1)
也只请求一个许可。
您还需要确保获得和释放相同数量的许可,除非您有非常 滥用 Semaphore
的充分理由。来自 Javadoc:
There is no requirement that a thread that releases a permit must have acquired that permit by calling acquire [or that a thread releases all of its permits]. Correct usage of a semaphore is established by programming convention in the application.
此外,您似乎为此任务使用了错误的同步器。您可以使用 CyclicBarrier
或其他 class usable for synchronization.
我花了一些时间才弄清楚你想要完成什么。这是我想出的。希望对你有帮助。
问题是您的实现中的线程试图按某种顺序获取锁。所以等待 3 个许可的线程首先等待,然后是等待 2 个许可的线程,显然排队等待他的 2 个许可,然后是第一个只想要 1 个许可的线程。有一个可用的许可证,所以很高兴。然后它 returns 2 许可。不幸的是,接下来是等待 3 个许可的线程,而不是等待 2 个许可的线程。真可惜。阻止。这就是你观察到的。
如果你让其他线程改变队列获取的位置,一切都会好起来的。来了
s.tryAcquire(int permits)
然后突然一切正常。
我会根据你的代码做一个例子,在繁忙的等待循环中休眠 1 秒,看看发生了什么。
import java.util.concurrent.Semaphore;
class Process0 extends Thread {
Semaphore s;
public Process0(Semaphore s){
this.s = s;
}
public void run(){
try {
sleep(20000);
s.acquire();
System.out.println("hello");
} catch (InterruptedException ex) {
System.out.println(Process.class.getName());
}
s.release(2);
System.out.println("released 2");
}
}
class Process1 extends Thread{
Semaphore s;
public Process1(Semaphore s){
this.s = s;
}
public void run(){
try {
this.sleep(10000);
while(!s.tryAcquire(2)) {
System.out.println("Busy waiting for 2 permits");
sleep(1000);
}
System.out.println("Hello 2");
} catch (InterruptedException ex) {
System.out.println(Process.class.getName());
}
s.release(3);
System.out.println("Released 3");
}
}
class Process2 extends Thread{
Semaphore s;
public Process2(Semaphore s){
this.s = s;
}
public void run() {
System.out.println("Acquire process 3 ");
while(!s.tryAcquire(3)) {
System.out.println("Busy waiting for 3 permits");
try {
sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Hello 3");
}
}
public class DaemonTest {
public static void main(String[] args) {
Semaphore s = new Semaphore(1);
Process0 p = new Process0(s);
Process1 p1 = new Process1(s);
Process2 p2 = new Process2(s);
p.start();
p1.start();
p2.start();
}
}