当前位置: 首页 > 知识库问答 >
问题:

Java信号量导致多线程死锁

慕迪
2023-03-14

在使用信号量时,我应该注意多线程问题吗?在我的测试之后,似乎有一段时间信号灯#release not cause acquire wake up,即使有足够的许可证。

底部是我的测试代码。

  1. 带有2个许可证的信号灯
  2. Thread3和Thread2先向上
  3. 线程3获取许可,等待锁,锁将由线程1通知
  4. 线程2获取许可,等待锁1,锁1将由线程3通知
  5. 线程1启动,线程1和线程2先睡眠30ms启动
  6. 线程1通知锁定,获取2个许可
  7. 线程3唤醒,通知锁1,睡眠(1)睡眠1毫秒对于线程2,先获取许可证,然后释放许可证
  8. 线程2唤醒,获取许可证,然后释放一个许可证,再释放另一个许可证

它将在随机迭代时导致死锁,并输出一些类似这样的日志。

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

这是死锁发生时我的脚印

共有3个答案

甘英光
2023-03-14

你是赖特,死锁发生了,因为释放没有发出驻车线程的信号。我发现了一些报告的错误http://bugs.java.com/view_bug.do?bug_id=7011859

钱经业
2023-03-14

java.util.concurrent.locks.AbstractQueuedSynsynizerSemaphore用来做一些同步工作。它具有FIFO属性,这会导致问题。

我有2个许可证,在thread-3发布一个许可证后,只有一个许可证可用,根据SemaphoreFIFO获取顺序,如果Mythread-3获取(2)发生在thread-2获取(1)之前,thread-3将永远阻塞。

我将信号量与fair=false一起使用,内部将初始化非空同步,它扩展了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);
    }
}

翟鸿振
2023-03-14

Semaphore只保留许可证的数量。来自Semaphore文档:

从概念上讲,信号量维护一组许可。每个{@link获取}在必要时阻塞,直到许可可用,然后获取它。每个{@link#释放}都会添加一个许可,可能会释放阻塞的获取者。但是,没有使用实际的许可对象;{@code Semaphore}只是保留可用数量的计数并相应地执行操作。

我的意思是程序应该关心同步。

信号量通常用于限制可以访问某些(物理或逻辑)资源的线程数

 类似资料:
  • 本文向大家介绍HashMap 多线程操作导致死循环问题?相关面试题,主要包含被问及HashMap 多线程操作导致死循环问题?时的应答技巧和注意事项,需要的朋友参考一下 主要原因在于 并发下的Rehash 会造成元素之间会形成一个循环链表。不过,jdk 1.8 后解决了这个问题,但是还是不建议在多线程下使用 HashMap,因为多线程下使用 HashMap 还是会存在其他问题比如数据丢失。并发环境下

  • 本文向大家介绍JAVA 多线程之信号量(Semaphore)实例详解,包括了JAVA 多线程之信号量(Semaphore)实例详解的使用技巧和注意事项,需要的朋友参考一下 java Semaphore 简介         信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。         一个计数信号量

  • 我有一个关于管理线程的简单问题。我有3个进程,它们与一个许可证共享相同的信号量。在正常情况下,第一道工序采用该许可证,第二道工序发放两个许可证。第二个过程版本3允许进行第三个过程。我举了一个例子来说明我的问题。 第一个: 第二道工序: } 最后一个: 问题是。当我运行这三个进程并确保进程3是第一个执行的进程时。我会死锁。进程2永远不会打印“Hello 3”,进程1永远不会打印“Hello 2”。为

  • 头文件 semaphore.h sys/stat.h fcntl.h 常用函数 函数 说明 [[sem_open sem_open]] 打开一个有名信号量 [[sem_close sem_close]] 关闭一个信号量 [[sem_unlink sem_unlink]] 删除一个信号量 [[sem_post sem_post]] 【V操作】释放操作:信号量的值加1 [[sem_wait sem_w

  • 主要内容:1 什么是Java线程死锁,2 Java线程死锁的例子1 什么是Java线程死锁 Java中的死锁是多线程的一部分。当线程正在等待由另一个线程获取的对象锁而第二个线程正在等待由第一个线程获取的对象锁时,可能会发生死锁。由于两个线程都在互相等待释放锁,因此这种情况称为死锁。 2 Java线程死锁的例子 输出结果为:

  • 1“如何确保线程按特定顺序执行”这个问题的答案是正确地使用join()方法(参考:http://beginnersbook.com/2015/03/thread-join-method-in-java-with-example/). 2 15.5中的一个问题在下面的CiCt第6版中按顺序调用。 假设我们有以下代码: “同一个Foo实例将传递给三个不同的线程。线程A将首先调用,线程B将调用第二个,线