关于Java Concurrnet包中的Semaphone类造成死锁的问题

请教一下,关于Semaphore调用acquire()方法时造成死锁的问题。
Semaphore类指定了3个许可证,且是指定公平锁方式;这里我开了3个线程,线程A,C只能获取一个许可证,线程B可以获取2个许可证;在运行时,有时只会执行完线程A,其线程B和线程C都静默了。

代码如下:

public class SemaphoreDemo1 {
  public static void main(String[] args) throws InterruptedException {
      Semaphore semaphore = new Semaphore(2, true);

      ReentrantLock reentrantLock = new ReentrantLock();

      Thread threadA = new Thread(new MyRunnable(1, semaphore, reentrantLock), "thread-A");

      Thread threadB = new Thread(new MyRunnable(2, semaphore, reentrantLock), "thread-B");

      Thread threadC = new Thread(new MyRunnable(1, semaphore, reentrantLock), "thread-C");

      threadA.start();
      threadB.start();
      threadC.start();
  }
}

class MyRunnable implements Runnable {

  private int n;

  private Semaphore semaphore;

  private ReentrantLock lock;

  public MyRunnable(int n, Semaphore semaphore, ReentrantLock lock) {
      this.n = n;
      this.semaphore = semaphore;
      this.lock = lock;
  }

@Override
public void run() {
    try {

        semaphore.acquire(n);

        System.out.println("剩余可用许可证: " +
                semaphore.drainPermits());

        System.out.println(Thread.currentThread().getName() + "执行完成。。。。");

    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
       semaphore.release(n);
    }
 }
}
1 个赞

我执行了几次,好像也没遇到 。这是不是剩下俩线程竞争资源的时候死锁了啊?

是的,内部并没有保证并发安全。

1 个赞

我发现打断点就有问题,不打断点就正常跑

老弟啊,你自己代码写的有问题呢,drainPermits()这个方法是 获取剩余可用的许可并将可用许可置0,你的线程A获得了一个许可后,你调用drainPermits方法,剩余许可就是0了,你还在finally里面释放了一个,此时只有一个可用的许可,线程B需要两个许可,当然获取不到了,所以就一直等待啊,自然就不会执行你的线程B和线程C了,建议看看drainPermits方法源码,勿乱套用方法,应该使用availablePermits

2 个赞