我在应用程序中遇到问题,其中运行了两个具有相同参数的线程,发生冲突。一种解决方案是使用同步块,但由于问题只发生在具有相同参数的线程上,因此效率非常低。我想到的一种方法是使用并发映射将param组合存储为键,将对象存储为值,每当线程开始操作时,它首先检查映射是否包含键(param组合),如果是,它将执行等待为该组合存储的对象。线程最后会从地图中删除此对象并在其上调用notify。这种方法的问题是为相同的param组合生成相同的对象。例如:如果thread1插入到map中,并调用notify并将其删除,则thread2可能会退出等待,但是其他线程永远不会出现,因为对象从地图中丢失了。
这个问题有不同的优雅方法吗?
答案 0 :(得分:0)
创建参数组合池。每次需要保证一个线程正在运行时,请调用Pool.acquire(params)
。
像这样使用:
使用不错的hashCode
和equals
包装参数。
在线程中:
synchronized(pool) {
pool.acquire(myParams);
}
// do the work
synchronized(pool) {
pool.release(myParams);
}
游泳池:
class Pool {
Set<Params> lockedParams;
// In Pool - note that this is synchronized!
void acquire(Params params) {
Params lock = lockedParams.get(params);
if(lock != null) {
// Locked by another thread
lock.wait();
}
lockedParams.add(params);
}
void release(Params params) {
Params lock = lockedParams.remove(params);
lock.notifyAll();
}
}
这是一个想法。您需要为现实案例添加一些错误处理(release()
中的finally
,在这种情况下,在lock
中处理null Pool.release()
等。)
答案 1 :(得分:0)
调用notifyAll
而不是notify
,以便通知所有等待的线程。为什么要从地图中删除同步对象?只是尝试获取该对象的锁定,如果线程成功,它进入临界区,否则它开始等待。
您可以为该等待添加超时,因此如果线程在某段时间内无法获取锁定,则会失败。这样你的代码就不会陷入僵局。
答案 2 :(得分:0)
如果您可以将参数(或其子集)表示为String,则可以在interned
字符串上进行同步。