我有一个关于管理线程的简单问题。我有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是第一个执行获取
的进程时。我会死锁。进程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();
我花了一些时间才知道你想要完成什么。这是我想到的。希望有帮助。
问题是您的实现中的线程试图以某种顺序获取锁。所以等待3个许可的线程首先等待,然后是等待2个许可的线程,显然排队等待他的2个许可,然后是第一个只想要1个许可的线程。有一个可用的许可,所以可以走了。然后它返回2个许可。不幸的是,下一个排队的是等待3个许可的线程,而不是等待2。糟糕。阻塞。这就是你观察到的。
若您让其他线程在acquire的队列中更改位置,那个么一切都会很好。来了
s.tryAcquire(int permits)
突然间,一切都很好。
我将根据您的代码进行示例,在忙等待循环中使用1s睡眠来查看发生了什么。
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();
}
}
您的信号量构造为new Semaphore(1)
,它只有一个可用的许可证可供获取。调用s.acquire(3)
将永远不会返回,因为信号量永远不会有三个可用的许可证。通过Process
获取单个许可证的尝试也会被阻止,因为收购是有序的并且Process2
“首先”到达:
发布
方法javadoc指出,当
其他一些线程为此信号量调用release()方法,当前线程下一个将被分配一个许可证。
这个最小的单线程示例将向您展示:
Semaphore s = new Semaphore(1);
s.acquire(2);
System.out.println("Didn't deadlock!");
解决方法是使用信号量。acquire()请求一个许可证,或信号量。获取(1),它也只需要一个许可证。
您还需要确保获得和发布相同数量的许可,除非您有很好的理由滥用信号量。来自Javadoc:
不要求释放许可证的线程必须通过调用acquire获得该许可证[或者线程释放其所有许可证]。信号量的正确使用是通过应用程序中的编程约定建立的。
此外,您可能为此任务使用了错误的同步器。您可以使用CyclicBarrier
或其他可用于同步的类。
在使用信号量时,我应该注意多线程问题吗?在我的测试之后,似乎有一段时间信号灯#release not cause acquire wake up,即使有足够的许可证。 底部是我的测试代码。 带有2个许可证的信号灯 Thread3和Thread2先向上 线程3获取许可,等待锁,锁将由线程1通知 线程2获取许可,等待锁1,锁1将由线程3通知 线程1启动,线程1和线程2先睡眠30ms启动 线程1通知锁定
问题内容: 我已升级到最新的Java 7 build 1.7.0_60-b19,但问题仍然存在。 我进行了另一个线程转储,发现了相同的问题:在DefaultCorrelatingMessageHandler锁调用中,所有DefaultMessageListenerContainers(计数为20)都由taskScheduler(entityScheduler-3)锁定。 这是调度程序和聚合器配置:
死锁概念 死锁(Deadlock)就是一个进程拿着资源A请求资源B,另一个进程拿着资源B请求资源A,双方都不释放自己的资源,导致两个进程都进行不下去。 示例程序 我们可以写代码模拟进程死锁的例子。 package main func main() { ch := make(chan int) <-ch } 运行结果 root@fa13d0439d7a:/go/src# go run de
问题内容: 信号量和自旋锁之间的基本区别是什么? 什么时候在自旋锁上使用信号灯? 问题答案: 自旋锁和信号灯的主要区别在于四点: 1.他们是什么 一个 自旋锁 是一个可能实现的锁,即一个由忙等待(“旋转”)来实现。信号量是锁的概括(或者相反,锁是信号量的特例)。通常( 但不是必须) ,自旋锁仅在一个进程内有效,而信号量也可用于在不同进程之间进行同步。 锁用于互斥,即 一次一个 线程可以获取该锁并继
问题内容: 我有一个Java Servlet应用程序,并且正在使用准备好的查询来更新SQL Server数据库表中的记录。 可以说我要执行。(是的,id是一个varchar) 我使用以下代码来实现此目的: 我发现运行JMeter脚本模拟2个用户时,此语句在数据库中导致死锁。 我想检查一下SQL事件探查器中的值,因此我使用了以下代码,因此可以检查这些值。 突然我的僵局消失了!遗憾的是,最后一种方法容
本文向大家介绍互斥锁死锁,包括了互斥锁死锁的使用技巧和注意事项,需要的朋友参考一下 死锁可以在使用互斥锁的多线程Pthread程序中发生。让我们看看它如何发生。未锁定的互斥锁由pthread_mutex_init()函数初始化。 使用pthread_mutex_lock()和pthread_mutex_unlock()获取并释放互斥锁。如果线程尝试获取锁定的互斥锁,则对pthread_mutex_