Java Semaphore导致多线程

时间:2017-06-13 05:05:00

标签: java multithreading deadlock semaphore

使用信号量时我应该处理多线程问题吗? 在我的测试似乎有一段时间后,即使有足够的许可,信号量#释放也不会导致获得唤醒。

底部是我的测试代码。

  1. 信号量有2个许可
  2. 首先
  3. thread-3和thread-2
  4. thread-3获取许可,等待lock,这将通过thread-1
  5. 通知
  6. thread-2获取许可,等待lock1,这将通过thread-3
  7. 通知
  8. thread-1启动,为thread-1睡眠30ms,第2次启动thread-2
  9. thread-1通知lock获得2次许可
  10. 线程3唤醒,通知lock1 sleep(1)睡眠1毫秒,线程2首先获得许可释放许可 < / LI>
  11. 线程2唤醒,获得许可然后释放许可并释放另一个许可
  12. 它会在随机迭代中导致死锁,并且输出这样的日志。

    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();
        }
    }
    

    这是我发生死锁时的踩踏

    enter image description here

3 个答案:

答案 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);
    }
}