使用信号量时我应该处理多线程问题吗? 在我的测试似乎有一段时间后,即使有足够的许可,信号量#释放也不会导致获得唤醒。
底部是我的测试代码。
lock
,这将通过thread-1 lock1
,这将通过thread-3 lock
,获得2次许可 lock1
, sleep(1)
睡眠1毫秒,线程2首先获得许可,释放许可 < / LI>
它会在随机迭代中导致死锁,并且输出这样的日志。
in 3, a = 2
in 2 ,a = 2
in in 2 lock 1, a = 0
in 1 , a = 0
acquire and release 3
in in 2 locked, a = 0
out 3 ,a = 0
in 1 locked, a = 0
acquire and release 2
out 2
out 1 ,a = 2
-------------------------------------------------------------- 0
in 2 ,a = 2
in 3, a = 1
in 1 , a = 0
in in 2 lock 1, a = 0
acquire and release 3
out 3 ,a = 1
//deadlock here
在线程3信号量释放许可后,不会导致线程2唤醒,然后线程1和线程3等待永远获取
bleow是我的测试代码
import java.util.concurrent.Semaphore;
/**
* Created by rqg on 6/10/17.
*/
public class WaitTest {
public static void main(String[] args) throws InterruptedException {
Semaphore semaphore = new Semaphore(2);
final Object lock = new Object();
final Object lock1 = new Object();
// testSemaphore(semaphore, lock, lock1);
for (int i = 0; i < 10000; i++) {
testSemaphore(semaphore, lock, lock1);
System.out.println("--------------------------------------------------------------------------------- " + i);
}
}
private static void testSemaphore(Semaphore semaphore, Object lock, Object lock1) throws InterruptedException {
Thread t1 = new Thread() {
@Override
public void run() {
try {
Thread.sleep(30);
synchronized (lock) {
lock.notify();
}
System.out.println("in 1 , a = " + semaphore.availablePermits());
semaphore.acquire(2);
System.out.println("in 1 locked, a = " + semaphore.availablePermits());
} catch (InterruptedException e) {
e.printStackTrace();
}
semaphore.release(2);
System.out.println("out 1 ,a = " + semaphore.availablePermits());
}
};
Thread t2 = new Thread() {
@Override
public void run() {
try {
System.out.println("in 2 ,a = " + semaphore.availablePermits());
semaphore.acquire();
synchronized (lock1) {
lock1.wait();
}
System.out.println("in in 2 lock 1, a = " + semaphore.availablePermits());
semaphore.acquire();
System.out.println("in in 2 locked, a = " + semaphore.availablePermits());
semaphore.release();
semaphore.release();
System.out.println("acquire and release 2");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("out 2");
}
};
Thread t3 = new Thread() {
@Override
public void run() {
try {
System.out.println("in 3, a = " + semaphore.availablePermits());
semaphore.acquire();
synchronized (lock) {
lock.wait();
}
synchronized (lock1) {
lock1.notify();
}
sleep(1);
semaphore.release();
System.out.println("acquire and release 3");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("out 3 ,a = " + semaphore.availablePermits());
}
};
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
}
}
这是我发生死锁时的踩踏
答案 0 :(得分:0)
信号量只保留许可证数量。来自Semaphore docs:
从概念上讲,信号量保持一组许可。每个{@link 必要时获取}块,直到有许可证,然后接受。每个{@link #release}都可能添加许可 释放阻塞收购者。但是,没有实际的许可对象 使用; {@code Semaphore}只保留数字 可用并采取相应行动。
我的意思是程序应该关心同步。
信号量通常用于限制线程数量 访问一些(物理或逻辑)资源
答案 1 :(得分:0)
你正在发生死锁,因为释放没有发出公园线索的信号。 我发现了一些错误 http://bugs.java.com/view_bug.do?bug_id=7011859
答案 2 :(得分:0)
java.util.concurrent.locks.AbstractQueuedSynchronizer
使用 Semaphore
做一些同步工作。 它具有FIFO属性,这会导致问题。
我有2个许可证,并且在第3个线程发布许可证后,根据Semaphore
FIFO获取订单,只有一个许可证可用,如果我的thread-3 acquire(2)
发生在thread-2 acquire(1)
之前, thread-3将永远阻止。
我使用信号量fair=false
,内部将NonfairSync
extends AbstractQueuedSynchronizer
。
下面的代码导致信号量始终流动FIFO获取顺序。
/**
*java.util.concurrent.locks.AbstractQueuedSynchronizer#doAcquireSharedInterruptibly
*/
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}