public class MyClass {
private List<Integer> resources = new ArrayList<>();
public synchronized Integer getAndRemoveResourceOrWait(Integer requestedResource) throws InterruptedException {
while(resources.stream().anyMatch((r) -> { return r >= requestedResource; })) {
wait();
}
Integer found = resources.stream().findFirst((r) -> {
return r >= requestedResource;
}).get();
resources.remove(found);
return found;
}
public void addResource(Integer resource) {
resources.add(resource);
notifyAll();
}
}
线程&#34; A&#34;不定期地使用随机值调用addResource。 一些其他线程主动调用getAndRemoveResourceOrWait。
让方法getAndRemoveResourceOrWait同时工作需要做些什么?
例如,线程&#34; X&#34;使用变量128调用getAndRemoveResourceOrWait,这在资源集合中不存在。所以,它等待它。在等待的时候,线程&#34; Y&#34;使用变量64调用getAndRemoveResourceOrWait,它存在于资源集合中。线程&#34; Y&#34;不应该等待线程&#34; X&#34;完成。
答案 0 :(得分:1)
让方法getAndRemoveResourceOrWait同时工作需要做些什么?
它只需要在与调用addResource(resource)
的其他线程上运行。
请注意,getAndRemoveResource
是阻塞(同步)操作,因为调用的线程被阻塞,直到得到答案。但是,一个调用getAndRemoveResource
的线程不会阻止另一个调用getAndRemoveResource
的线程。关键是wait()
调用释放互斥锁,然后在通知互斥锁时重新获取互斥锁。这里会发生的是notifyAll
将导致所有等待的线程一次一个。
但是,您的addResource
方法存在错误。该方法需要声明为synchronized
。如果您在当前线程持有notifyAll()
的互斥锁时没有调用this
,则会出现异常。 (这也是确保共享resources
对象的更新在两个方向都可见的必要条件。)
此外,这种实施方式不会很好地扩展:
addResource
。MyClass
实例上持有互斥锁的时候完成的......这也阻止了addResource
。 更新 - 假设Resource
值是唯一的,更好的解决方案是将ArrayList
替换为TreeSet
。这应该有效:
public class MyClass {
private TreetSet<Integer> resources = new TreeSet<>();
public synchronized Integer getAndRemoveResourceOrWait(
Integer resource) throws InterruptedException {
while (true) {
Integer found = resources.tailSet(resource, true).pollFirst();
if (found != null) {
return found;
}
wait();
}
}
public synchronized void addResource(Integer resource) {
resources.add(resource);
notifyAll();
}
}
(我也试过了ConcurrentSkipListSet
但是我无法找到一种方法来避免在添加和删除时使用互斥锁。如果你试图删除相同的资源,可以做到...... )