在我的程序中,我有两种方法:
public void methodA() { //gets called very often
//write something to file
}
public void methodB() {
//write something to file
}
methodA
经常被客户端调用,而methodB
只会不时调用。但是,我需要确保无论何时客户端想要调用methodB
它都可以这样做(在methodA
可能的当前执行完成之后)。我尝试在每个方法中引入一个带锁定对象的同步块,但methodB
似乎饿死了,因为methodA
被更频繁地调用。
我该如何解决这个问题?
答案 0 :(得分:10)
听起来你需要一个公平 Lock
。要制作其中一个,您应该将true
作为参数传递给构造函数。
Lock lock = new ReentrantLock(true);
public void methodA() {
lock.lock();
try {
// Write something to a file.
} finally {
lock.unlock();
}
}
public void methodB() {
lock.lock();
try {
// Write something to a file.
} finally {
lock.unlock();
}
}
答案 1 :(得分:2)
ReentrantLock
有一个constructor,其中包含一个公平参数,可以防止你的情况出现饥饿。
答案 2 :(得分:2)
如果你想优先考虑方法B而不是方法A,这是我能想到的最简单的事情:
private Object writeLock = new Object();
private Object highPriorityLock = new Object();
private int highPriorityLockReleaseCount = 0;
private int highPriorityLockLockCount = 0;
public void methodA() {
synchronized (writeLock) {
synchronized (highPriorityLock) {
// Wait until there are no more highPriorityLocks
while (highPriorityLockLockCount != highPriorityLockReleaseCount) {
highPriorityLock.wait();
}
}
// Do write (thread holds write lock)
}
}
public void methodB() {
synchronized (highPriorityLock) {
// Get current lock count
int lockCount = highPriorityLockLockCount;
// Increment lock count by one
highPriorityLockLockCount++;
// Wait until lock is acquired (current release count reaches saved lock count)
while (lockCount != highPriorityLockReleaseCount) {
highPriorityLock.wait();
}
}
synchronized (writeLock) {
// Do write (thread holds write lock)
}
synchronized (highPriorityLock) {
// Relase high priority lock by incrementing current counter
highPriorityLockReleaseCount++;
highPriorityLock.notifyAll();
}
}
确保处理异常并确保始终正确释放高优先级锁
答案 3 :(得分:1)
我建议优先处理队列。简单地说,有两个队列,一个用于方法A,另一个用于方法B.在下面的逻辑中处理队列的另一个线程:当B的队列不为空时,操作它,否则,为A队列。
答案 4 :(得分:1)
您可以使用semaphores。它基本上适用于你将字段设置为某个值的想法。让我们说锁定。而另一种方法,你做了一段时间..重复无限,直到其他过程完成。您可以通过在diffirent线程中调用该方法来使用信号量。并使用关键字synchronized void ..
信号量部分是硬件部分软件解决方案。还有纯软件解决方案。例如Peterson's algorithm
答案 5 :(得分:1)
如果您的主要问题是methodB
来电不被阻止或者饿死,您可以通过非阻塞I / O操作来解决并发问题
Java NIO.2 java.nio.channels.AsynchronousFileChannel可以满足这些需求。您可以找到一个很好的用法说明和示例here。
答案 6 :(得分:0)
这与this question大致相同。该问题的最高评价答案有三种选择。选项2和3都假设methodB
将始终从同一个线程调用,您没有说过这种情况,但选项1应该有效。移植到Java的选项1是:
private final Lock m = new ReentrantLock();
private final Lock n = new ReentrantLock();
private final Lock l = new ReentrantLock();
public void methodA() {
l.lock();
n.lock();
m.lock();
n.unlock();
try {
doA();
} finally {
m.unlock();
l.unlock();
}
}
public void methodB() {
n.lock();
m.lock();
n.unlock();
try {
doB();
} finally {
m.unlock();
}
}
这给方法B绝对优先于方法A,不像OldCurmudgeon的答案,它给出了两个相同的优先级。如果您还希望算法公平(除了methodB
优先于methodA
),您应该使锁n
和l
公平。 m
的公平性并不重要。