Java Semaphore cause deadlock on multithread
使用信号量时,我应该解决多线程问题吗?
经过一段时间的测试后,即使有足够的许可,Semaphore#release也不会导致获取唤醒。
底部是我的测试代码。
它将在随机迭代时导致死锁,并输出这样的日志。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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是我的测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | 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(); } } |
这是发生死锁时我的脚下倾倒物
我有2个许可,并且在线程3释放许可之后,只有一个许可可用,根据
我将信号量与
以下代码导致信号量始终流FIFO获取顺序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | /** *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); } } |
您很清楚,由于释放未指示驻留线程,因此发生了死锁。
我发现为此报告了一些错误
http://bugs.java.com/view_bug.do?bug_id=7011859
信号量仅保留许可数量。来自Semaphore文档:
Conceptually, a semaphore maintains a set of permits. Each {@link
acquire} blocks if necessary until a permit is available, and then takes it. Each {@link #release} adds a permit, potentially
releasing a blocking acquirer. However, no actual permit objects
are used; the {@code Semaphore} just keeps a count of the number
available and acts accordingly.
我的意思是程序应该注意同步。
Semaphores are often used to restrict the number of threads than can
access some (physical or logical) resource