Java实现选择性同步

发布于 2024-12-12 13:23:05 字数 299 浏览 0 评论 0原文

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

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

I'm facing a problem in an application where two threads with same parameters are run, a conflict occurs. One solution was to use a synchronized block, but since the problem occurs only for threads with same params, it would be highly inefficient. One way I thought of was to use a concurrent map to store the param combination as key and an object as value, whenever a thread begins the operation it first checks if the map contains the key (param combination) and if so, it will do a wait on the object stored for that combination. The thread would at the end remove this object from the map and invoke notify on it. The problem with this approach is generating the same object for the same param combination. For ex: if thread1 inserts into map, and calls notify and removes it, thread2 may come out of wait, but other threads will never come out as the object is lost from the map.

Is there a different elegant approach to this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

蝶舞 2024-12-19 13:23:05

创建参数组合池。每次需要保证一个线程正在运行时,请调用 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();
  }
}

这是一个想法。您需要为现实生活中的情况添加一些错误处理(finally 中的 release(),在本例中处理 Pool 中的 null lock .release() 等)。

Create a pool of parameter combinations. Every time you need to guarantee one thread is running, call Pool.acquire(params).

Use it like this:

Wrap parameters in an object with nice hashCode and equals.

In Thread:

synchronized(pool) {
  pool.acquire(myParams);
}
// do the work
synchronized(pool) {
  pool.release(myParams);
}

Pool:

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();
  }
}

That's one idea. You need to add some error handling for real life cases (release() in finally, in this case handle null lock in Pool.release(), etc.).

南笙 2024-12-19 13:23:05

调用 notifyAll 而不是 notify,因此所有等待线程都会收到通知。为什么要从地图中删除同步对象?只需尝试获取该对象的锁,如果线程成功,则进入临界区,否则开始等待。

您可以为该等待添加超时,因此如果线程在一段时间内无法获取锁,则会失败。这样你的代码就不会陷入死锁。

Call notifyAll instead of notify, so all waiting threads will be notified. And why do you want to remove sync object from map? Just try to acquire lock on that object, if thread succeeds, it enters critical section, otherwise it starts to wait.

You can add timeout to that wait, so if thread can't acquire lock for some period, it fails. This way your code won't go into deadlock.

前事休说 2024-12-19 13:23:05

如果您可以将参数(或其子集)表示为字符串,则可以在 interned 字符串上进行同步。

If you can represent the parameters (or a subset of them) as a String, you can synchronize on the interned string.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文