睡眠线程以避免线程饥饿



我有一个在无限循环中运行的线程正在执行一些代码,它将获得一个Lock
同时,我有另一个线程在执行计划任务,也需要获取锁才能执行某些操作
为了确保在锁被无限循环占用太长时间的情况下,调度任务不会被饿死,我在解锁后让线程睡了一会儿。我认为这是一个合理的举动,而不是过分夸张,前提是我不介意睡眠带来的性能成本
还有一个后续问题:我看到其他人也在做同样的事情,但不是睡一段固定的时间,而是睡一段随机的时间ThreadUtil.sleep(RandomUtil.nextInt(5, 100)),但我无法理解这样做的好处。

private final Lock writeLock = new ReentrantLock(true);
while (true) {
writeLock.tryLock(100, TimeUnit.MILLISECONDS);
try {
doSomething();
} finally {
writeLock.unlock();
}

// food for everyone!
ThreadUtil.sleep(10);
}

需要澄清的几点和后续问题:

  1. 调度任务在超时(writeLock.tryLock(100, TimeUnit.MILLISECONDS))的情况下获取锁,这与无限循环线程的操作方式相同
  2. 除了调度任务之外,实际上还有另一个用例可以手动触发函数(通过ws调用)并获取锁来执行某些操作
  3. 问题是:如果无限循环线程根本不休眠,我假设其他线程最终仍将被执行,只是可能会有一段不确定的时间延迟

至少在您描述的场景中,我看不出像ThreadUtil.sleep(RandomUtil.nextInt(5, 100))这样的随机睡眠时间有任何好处。你的ThreadUtil.sleep(10);也会做同样的工作。

唯一的问题是我不确定你安排的任务线程是如何获得锁的。我认为它还会有一个循环,每隔x毫秒(比如10毫秒)检查锁是否被释放只要你只有两个线程(一个有锁,另一个试图获取锁),你就应该没事但假设我们有三条线索线程具有锁&B&C线程正在执行循环以获取锁。如果B线程总是出现&在C线程&锁由A线程在该时间间隔内释放,C线程&B线程,因为时间表是可预测的让它变得不可预测&确保所有三个线程都有机会获得锁,睡眠时间中的一些随机性是必要的

但我认为有一个比睡眠更好的解决方案;收购wait()&notifyAll()更适合这里线程A在特定间隔后对某个对象调用notify()&开始等待。线程B&C已经在等待同一个对象。他们中的一个将被通知&获取锁。假设C这次得到了锁。如果C没有一些计划任务,它将立即再次调用notify()。然后A或B中的一个将获得锁谁获得锁将由JVM&它将有更好的实现,这样一个线程就不会饿死

最新更新