簡體   English   中英

Java同步對象

[英]Java synchronize on object

如何同步來自同一個類的兩個不同方法以鎖定同一個對象? 下面是一個例子:

public class MyClass extends Thread implements Observer{
  public List<AnotherClass> myList = null;
  
  public MyClass(List<AnotherClass> myList){
    this.myList = myList;
  }
  
  public void run(){
    while(true){
       //Do some stuff 
       myList.add(NotImportantElement);
    }
  }

  public void doJob{
    for(int i=0; i<myList.size; i++){
      ElementClass x = myList.get(i);
      //Do some more stuff
    }
  }
}

問題是如何在執行 doJob 時阻止 run() 訪問 myList,反之亦然?

想象一下:我啟動線程並開始向我的列表添加元素。 在一個隨機時刻,我從另一個持有對我的線程的引用的類調用 doJob()。

我應該怎么做鎖? 謝謝!

好的,我理解了鎖的概念,但現在我有另一個問題。

假設我有一個帶有public static myList的類,並且只有該類的一個實例。 從那個實例中,我創建了nThread實例,它們獲取該列表的每個元素並用它做一些事情。

現在,在特定時刻更新myList 那些已經在處理 myList 元素的線程會發生什么? 我應該如何在更新myList時鎖定myList訪問?

注意:此代碼假定您只有一個 MyClass 實例。 根據你的帖子,聽起來是這樣。

public class MyClass extends Thread implements Observer{
  private List<AnotherClass> myList = null;
  private Object lock = new Object();

  public MyClass(List<AnotherClass> myList){
    this.myList = new ArrayList(myList);
  }

  public void run(){
    while(true){
       //Do some stuff 
       synchronized(lock) {
        myList.add(NotImportantElement);
       }
    }
  }

  public void doJob{
    synchronized(lock) {
      for(int i=0; i<myList.size; i++){
        ElementClass x = myList.get(i);
        //Do some more stuff
      }
    }
  }
}

編輯:添加了制作 List 的副本,以便外部實體無法按照 JB Nizet 更改列表

編輯 2:將變量設為私有,以便其他人無法訪問它們

你可以:

  1. 聲明rundoJob synchronized 這將使用this作為鎖;
  2. 將列表聲明為final列表並對其進行同步。 這將使用列表作為鎖。 將鎖定字段聲明為final是一種很好的做法。 這樣,您的類的某些方法可以在一個對象上同步,而其他方法可以使用其他對象進行同步。 這減少了鎖爭用,但增加了代碼復雜性;
  3. 引入顯式java.util.concurrent.locks.Lock變量並使用它的方法進行同步。 這將提高代碼的靈活性,但也會增加代碼的復雜性;
  4. 不要完全進行顯式同步,而是使用 JDK 中的一些線程安全數據結構。 例如, BlockingQueueCopyOnWriteArrayList 這將降低代碼復雜度並確保線程安全。
  5. 通過讀取/寫入volatile字段來實現同步。 請參閱SO 帖子。 這將確保安全,但會大大增加復雜性。 第二個想法,不要這樣做:)

您可以添加

同步

兩種方法的關鍵字或使用

synchronized(Myclass.class) {
}

前者本質上使用 Myclass.class 對象,但它不像后者那樣細粒度。

將這兩種方法聲明為synchronized以鎖定每個實例,或者使用synchronized(this){...}塊只鎖定當前實例。

synchronized(myList) {
    // do stuff on myList
}

具體文檔: Intrinsic Locks and Synchronization

然而,我鼓勵您使用線程安全的並發數據結構來實現您想要實現的目標,以避免同步並獲得(很多)更好的性能:並發包摘要

暫無
暫無

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

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