首页 > 解决方案 > ReentrantLock 条件的优先级

问题描述

问题:我有一组Threads,其中一些在获取 时必须优先于其他ReentrantLock

解决方案:我可以想象有一个有 2 个队列的公平 :和. 点是之前发出的信号。考虑到公平性,一定会发生sblocked in总是先于sblocked on。ReentrantLockConditionlowPriorityhighPriorityhighPrioritylowPriorityReentrantLockThreadhighPriorityThreadlowPriority

执行:

public class Main {
    public static final Lock lock = new ReentrantLock(true);
    public static final Condition lowPriority = lock.newCondition();
    public static final Condition highPriority = lock.newCondition();
    public static boolean cond;

    public static void lowPriority() throws InterruptedException {
        try {
            lock.lock();
            while(!cond) {
                lowPriority.await();
            }
            cond = false;
            System.out.println("low");
        } finally {
            lock.unlock();
        }
    }

    public static void highPriority() throws InterruptedException {
        try {
            lock.lock();
            while(!cond) {
                highPriority.await();
            }
            cond = false;
            System.out.println("high");
        } finally {
            lock.unlock();
        }
    }

    public static void setCond(){
        try{
            lock.lock();
            cond = true;
            highPriority.signalAll();
            lowPriority.signalAll();
        } finally {
            lock.unlock();
        }
    }
}

问题:让我对解决方案感到困惑的问题是,我无法从 JMM 的角度正式证明,只要有Threads 被阻止,highPriority他们总是会赢得Threads 被阻止lowPriority

当然,我进行了一些实验,高优先级的线程总是获胜,但它在形式上是正确的吗?

标签: javamultithreadingconcurrencyjvmreentrantlock

解决方案


据我了解,对于代码

highPriority.signalAll();
lowPriority.signalAll();

不能保证某个等待的线程highPriority会在任何等待的线程之前唤醒lowPriority
即使fairness==true线程可以按随机顺序唤醒1

但是请注意,锁的公平性并不能保证线程调度的公平性。因此,使用公平锁的许多线程之一可能会连续多次获得它,而其他活动线程没有进展并且当前没有持有锁。

此外,lowPriority.signalAll()即使一个新的高优先级线程出现在该进程的中间,它也会继续唤醒所有低优先级线程。

所以我会在附加逻辑的开头插入lowPriority,它检查是否有任何等待的高优先级线程,如果有,让它们先运行。
像这样的东西:

public final class Main {

  private final Lock lock = new ReentrantLock();
  private final Condition lowPriority = lock.newCondition();
  private final Condition highPriority = lock.newCondition();
  private int numWaitingHighPriority = 0;
  private boolean cond;

  public void lowPriority() throws InterruptedException {
    lock.lock();
    try {
      while (!cond || (numWaitingHighPriority > 0)) {
        if (numWaitingHighPriority > 0) {
          highPriority.signal();
        }
        lowPriority.await();
      }
      cond = false;
      System.out.println("low");
    } finally {
      lock.unlock();
    }
  }

  public void highPriority() throws InterruptedException {
    lock.lock();
    try {
      numWaitingHighPriority++;
      try {
        while (!cond) {
          highPriority.await();
        }
      } finally {
        numWaitingHighPriority--;
      }
      cond = false;
      System.out.println("high");
    } finally {
      lock.unlock();
    }
  }

  public void setCond() {
    lock.lock();
    try {
      cond = true;
      ((numWaitingHighPriority > 0) ? highPriority : lowPriority).signal();
    } finally {
      lock.unlock();
    }
  }
}

推荐阅读