我的班级有以下锁定机制。当我运行这个程序时,一个线程不断获取并重新获取锁定,而不给任何其他线程获取锁定的机会,导致饥饿。如何重构我的锁定机制,以便一旦线程放弃锁定,另一个获取它?我希望看到其他线程获得锁定,而不必等到锁定停止运行。“
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private final Map<Integer, Long> locksMap = new HashMap<Integer, Long>();
/** {@inheritDoc} */
@Override
public long lock(int recNo) throws RecordNotFoundException {
ValidationUtils.checkNegative(recNo);
lock.lock();
long id = Thread.currentThread().getId();
try {
while (locksMap.get(recNo) != null) {
try {
System.out.println("Thread " + id + " is waiting.");
condition.await();
}
catch (InterruptedException e) {
LOGGER.log(Level.SEVERE, e.getMessage());
return -1;
}
}
Long prevValue = locksMap.put(recNo, id);
if (prevValue != null) {
String msg = "Expected no value for " + recNo + " but was ";
msg += prevValue + ".";
throw new IllegalStateException(msg);
}
System.out.println("Thread " + id + " has the lock.");
}
finally {
lock.unlock();
}
return id;
}
/** {@inheritDoc} */
@Override
public void unlock(int recNo, long cookie) throws RecordNotFoundException, SecurityException {
ValidationUtils.checkNegative(recNo);
if (cookie < 0) {
throw new IllegalArgumentException("cookie is negative.");
}
lock.lock();
try {
if (locksMap.get(recNo) == cookie) {
locksMap.remove(recNo);
}
else {
String msg = "Wrong lock cookie. Expected " + locksMap.get(recNo);
msg += ", was " + cookie + ".";
throw new IllegalStateException(msg);
}
long id = Thread.currentThread().getId();
System.out.println("Thread " + id + " no longer has the lock.");
condition.signalAll();
}
finally {
lock.unlock();
}
}
/**
* Tests the locking mechanism in this class.
*
* @param args None.
*/
public static void main(String... args) {
ExecutorService threadPool = Executors.newFixedThreadPool(5);
final CountDownLatch latch = new CountDownLatch(5);
final Data data = new Data();
Runnable task = new Runnable() {
@Override
public void run() {
try {
for (int index = 0; index < 10; index++) {
long cookie = data.lock(1);
Thread.sleep(1000); // Do something.
data.unlock(1, cookie);
}
}
catch (SecurityException e) {
e.getStackTrace();
}
catch (RecordNotFoundException e) {
e.getStackTrace();
}
catch (InterruptedException e) {
e.getStackTrace();
}
finally {
latch.countDown();
}
}
};
for (int index = 0; index < 5; index++) {
threadPool.execute(task);
}
try {
latch.await();
}
catch (InterruptedException e) {
e.getStackTrace();
}
threadPool.shutdown();
}
这是输出。请注意,只有在循环结束后,线程9才会停止获取锁定。
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
答案 0 :(得分:9)
将ReetrantLock
与公平政策一起使用。公平政策避免线程饥饿。
private final ReentrantLock lock = new ReentrantLock(true);
Java doc
public ReentrantLock(boolean fair) 使用给定的公平策略创建ReentrantLock的实例。 参数: 公平 - 如果这个锁是公平的,那就是真的;否则错误
答案 1 :(得分:4)
我知道你已经有了一个可以接受的答案,但我只是想加上我的2¢。
如果您在单核计算机上运行,或者甚至可能在双核计算机上运行,那么问题可能只是JVM没有经常交换线程以使另一个线程有机会锁定。
在任何情况下,只需在释放锁之后调用Thread.yield()
就足以让其他线程有机会在原始线程再次获取锁之前获取锁。
答案 2 :(得分:2)
通常,锁不应长时间保持。所以
long cookie = data.lock(1);
Thread.sleep(1000); // Do something.
data.unlock(1, cookie);
是不可接受的。这种方式总是只有一个线程每时每刻都“做点什么”。即使您按照建议添加yeild()或sleep(),吞吐量性能也保持不变。你应该获取锁定,检索任务,释放锁定,然后“做某事”。
答案 3 :(得分:0)
一旦线程放弃锁定,为什么不使用Thread.sleep(int millis)让它睡眠时间足以让另一个线程获取它?