Java实现了选择性同步

时间:2011-10-28 11:31:41

标签: java multithreading

我在应用程序中遇到问题,其中运行了两个具有相同参数的线程,发生冲突。一种解决方案是使用同步块,但由于问题只发生在具有相同参数的线程上,因此效率非常低。我想到的一种方法是使用并发映射将param组合存储为键,将对象存储为值,每当线程开始操作时,它首先检查映射是否包含键(param组合),如果是,它将执行等待为该组合存储的对象。线程最后会从地图中删除此对象并在其上调用notify。这种方法的问题是为相同的param组合生成相同的对象。例如:如果thread1插入到map中,并调用notify并将其删除,则thread2可能会退出等待,但是其他线程永远不会出现,因为对象从地图中丢失了。

这个问题有不同的优雅方法吗?

3 个答案:

答案 0 :(得分:0)

创建参数组合池。每次需要保证一个线程正在运行时,请调用Pool.acquire(params)

像这样使用:

使用不错的hashCodeequals包装参数。

在线程中:

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字符串上进行同步。