簡體   English   中英

Java一致同步

[英]Java consistent synchronization

我們在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 ...構建的順序。

謝謝

你最好的選擇是暴露一個“當前狀態”對象並使用volatile,拋棄所有同步代碼。 (另外,您可能希望使列表不可修改的包裝器只是為了安全)。

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

構建新列表只是為了將其復制到另一個(最終)列表中,這有點浪費。

在構建列表之后(在updateRunOnceEveryFiveMinutes )考慮使用不可變列表並將新列表分配給_sync.a_sync.b_sync.c (已從中刪除了final修飾符)。

您還在同步4個不同的對象。 對於每個方法調用,僅對一個對象( _sync或可能是專用鎖對象)進行同步會更簡單。

如果getListA等返回的列表是不可變的,那么您也不需要調用Collections.synchronizedList

草案沒有達到你的目標。 這里沒有任何東西阻止在計算新的A或B時訪問舊的C. 實現這一目標的最簡單方法是:

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

圍繞所有訪問,無論是讀還是寫。 我不會做clear()和addAll(),只需將變量值更改為newA / newB / newC,雖然這需要對上面的內容進行一些調整。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM