Java一致性同步

发布于 2024-10-11 12:08:59 字数 1630 浏览 3 评论 0原文

我们在Spring服务中,在多线程环境中面临以下问题:

  • 三个列表被自由且独立地偶尔(每5分钟)读取
  • 一次,它们都被更新为新值。列表之间存在一些依赖性,例如,当第二个列表正在更新且第一个列表已具有新值时,不应读取第三个列表;这将打破三个列表的一致性。

我最初的想法是创建一个具有三个列表作为属性的容器对象。
然后,首先在该对象上进行同步,然后在三个列表中逐一进行同步。

有些代码值得几千字......所以这是一个草案

    private class Sync {
        final List<Something> a = Collections.synchronizedList(new ArrayList<Something>());
        final List<Something> b = Collections.synchronizedList(new ArrayList<Something>());
        final List<Something> c = Collections.synchronizedList(new ArrayList<Something>());
    }

    private Sync _sync = new Sync();

   ...

   void updateRunOnceEveryFiveMinutes() {
     final List<Something> newa = new ArrayList<Something>();
     final List<Something> newb = new ArrayList<Something>();
     final List<Something> newc = new ArrayList<Something>();

     ...building newa, newb and newc...

     synchronized(_sync) {

        synchronized(_sync.a) {
            _synch.a.clear();
            _synch.a.addAll(newa);
        }

        synchronized(_sync.b) { ...same with newb... }

        synchronized(_sync.c) { ...same with newc... }
   }

   // Next is accessed by clients

   public List<Something> getListA() {
      return _sync.a;
   }

   public List<Something> getListB() { ...same with b... }

   public List<Something> getListC() { ...same with c... }

问题是,

  • 这个草案安全吗(没有死锁,数据一致性)?
  • 针对该具体问题您有更好的实施建议吗?

更新

更改了 _sync 同步和 newa... 构建的顺序。

谢谢

We are facing the following problem in a Spring service, in a multi-threaded environment:

  • three lists are freely and independently accessed for Read
  • once in a while (every 5 minutes), they are all updated to new values. There are some dependencies between the lists, making that, for instance, the third one should not be read while the second one is being updated and the first one already has new values ; that would break the three lists consistency.

My initial idea is to make a container object having the three lists as properties.
Then the synchronization would be first on that object, then one by one on each of the three lists.

Some code is worth a thousands words... so here is a draft

    private class Sync {
        final List<Something> a = Collections.synchronizedList(new ArrayList<Something>());
        final List<Something> b = Collections.synchronizedList(new ArrayList<Something>());
        final List<Something> c = Collections.synchronizedList(new ArrayList<Something>());
    }

    private Sync _sync = new Sync();

   ...

   void updateRunOnceEveryFiveMinutes() {
     final List<Something> newa = new ArrayList<Something>();
     final List<Something> newb = new ArrayList<Something>();
     final List<Something> newc = new ArrayList<Something>();

     ...building newa, newb and newc...

     synchronized(_sync) {

        synchronized(_sync.a) {
            _synch.a.clear();
            _synch.a.addAll(newa);
        }

        synchronized(_sync.b) { ...same with newb... }

        synchronized(_sync.c) { ...same with newc... }
   }

   // Next is accessed by clients

   public List<Something> getListA() {
      return _sync.a;
   }

   public List<Something> getListB() { ...same with b... }

   public List<Something> getListC() { ...same with c... }

The question would be,

  • is this draft safe (no deadlock, data consistency)?
  • would you have a better implementation suggestion for that specific problem?

update

Changed the order of _sync synchronization and newa... building.

Thanks

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

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

发布评论

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

评论(3

各自安好 2024-10-18 12:08:59

你最好的选择是公开一个“当前状态”对象并使用易失性,放弃所有同步代码。 (另外,为了安全起见,您可能希望使列表成为不可修改的包装器)。

public class ListState {
  List final a;
  List final b;
  List final c;
}

private volatile ListState _state;

void updateRunOnceEveryFiveMinutes() {
  // generate new lists ...

  // re-assign current list state (e.g. atomically publish all your updates)
  _state = new ListState(newA, newB, newC);
}

public ListState getCurrentLists() {
  return _state;
}

your best option is to expose a "current state" object and use volatile, ditching all the synchronized code. (also, you may want to make the lists unmodifiable wrappers just to be safe).

public class ListState {
  List final a;
  List final b;
  List final c;
}

private volatile ListState _state;

void updateRunOnceEveryFiveMinutes() {
  // generate new lists ...

  // re-assign current list state (e.g. atomically publish all your updates)
  _state = new ListState(newA, newB, newC);
}

public ListState getCurrentLists() {
  return _state;
}
染火枫林 2024-10-18 12:08:59

构建一个新列表只是将其复制到另一个(最终)列表中有点浪费。

考虑使用不可变列表并将新列表分配给 _sync.a_sync.b_sync.c(已删除 final构建列表后(在 updateRunOnceEveryFiveMinutes 中)。

此外,您还在 4 个不同的对象上进行同步。对于每个方法调用,仅同步一个对象(_sync 或可能是一个专用锁对象)会更简单。

如果 getListA 等返回的列表是不可变的,您也不需要调用 Collections.synchronizedList。

It's a bit wasteful to build a new list only to copy it into another (final) list.

Consider using immutable lists and assigning the new list to _sync.a, _sync.b and _sync.c (having removed the final modifier from them) after building the list (in updateRunOnceEveryFiveMinutes.)

Also you are synchronizing on 4 different objects. It would be simpler to synchronize on just one object (_sync or possibly a dedicated lock object) for each method call.

If the lists returned by getListA etc. are immutable you do also not need the calls to Collections.synchronizedList.

呆橘 2024-10-18 12:08:59

草案没有实现你的目标。这里没有任何东西可以阻止在计算新的 A 或 B 时访问旧的 C。实现这一点的最简单方法如下:

synchronized (a) {
  synchronized (b) {
    synchronized (c) {
    }
  }
}

围绕所有访问,无论是读还是写。我不会执行clear()和addAll(),只需将变量值更改为newA/newB/newC,尽管这需要对上述内容进行一些调整。

The draft doesn't accomplish your objective. There is nothing here that prevents access to the old C while the new A or B are being computed. The simplest way to accomplish that is like so:

synchronized (a) {
  synchronized (b) {
    synchronized (c) {
    }
  }
}

around all accesses whether read or write. And I wouldn't do clear() and addAll(), just change the variable value to newA/newB/newC, although that would require some adjustment to the above.

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