簡體   English   中英

java arraylist上的易失性/同步

[英]java Volatile/synchronization on arraylist

我的程序看起來像這樣:

public class Main {
    private static ArrayList<T> list;

    public static void main(String[] args) {
        new DataListener().start();
        new DataUpdater().start();
    }

    static class DataListener extends Thread {
        @Override
        public void run() {
            while(true){
                //Reading the ArrayList and displaying the updated data
                Thread.sleep(5000);
            }
        }
    }

    static class DataUpdater extends Thread{
        @Override
        public void run() {
            //Continuously receive data and update ArrayList;
        }
    }
}

為了在兩個線程中使用這個ArrayList,我知道兩個選項:

  1. 使ArrayList易變。 但是,我在本文中讀到,只有在“寫入變量不依賴於其當前值”時才允許變量volatile。 我認為在這種情況下它(因為例如當你對ArrayList執行添加操作時,此操作之后的ArrayList的內容取決於ArrayList的當前內容,或者不是嗎?)。 此外,DataUpdater必須時不時地從列表中刪除一些元素,我還讀到不可能從不同的線程編輯volatile變量。

  2. 使此ArrayList成為同步變量。 但是,我的DataUpdater會不斷更新ArrayList,所以這不會阻止DataListener讀取ArrayList嗎?

我是否誤解了這里的任何概念,還是有其他選擇使這成為可能嗎?

揮發性對你沒有任何幫助。 volatile的含義是線程A對共享變量所做的更改立即對線程B可見。 通常這樣的更改可能在某些緩存中僅對構成它們的線程可見,而volatile只是告訴JVM不要進行任何緩存或優化,這將導致值更新被延遲。

所以它不是一種同步手段。 這只是確保變革可見性的一種手段。 而且,它是變量的變化,而不是變量 引用對象 也就是說,如果您標記listvolatile ,只會讓任何區別,如果您分配一個新的列表, list ,如果你不改變列表的內容!


您的另一個建議是使ArrayList成為同步變量。 這里有一種誤解。 變量無法同步。 唯一可以同步的是代碼 - 整個方法或其中的特定塊。 您使用對象作為同步監視器

監視器本身就是對象(實際上,它是作為監視器的對象的邏輯部分),而不是變量。 如果在同步舊值后將其他對象分配給同一變量,則不會使舊顯示器可用。

但無論如何,它不是同步的對象,而是您決定使用該對象進行同步的代碼。

因此,您可以使用list作為監視器來同步其上的操作。 但是你不能讓list同步。


假設您要使用列表作為監視器來同步您的操作,您應該設計它,以便編寫器線程不會一直保持鎖定。 也就是說,它只是抓取它進行單個讀取更新,插入等,然后釋放它。 再次抓取它進行下一次操作,然后釋放它。 如果同步整個方法或整個更新循環,則另一個線程將永遠無法讀取它。

在閱讀主題中,你應該做的事情如下:

List<T> listCopy;

synchronized (list) {
    listCopy = new ArrayList(list);
}

// Use listCopy for displaying the value rather than list

這是因為顯示可能很慢 - 它可能涉及I / O,更新GUI等。因此,為了最小化鎖定時間,您只需從列表中復制值,然后釋放監視器,以便更新線程可以完成其工作。


除此之外, java.util.concurrent包等中有許多類型的對象,旨在幫助這樣的情況,其中一方是寫,另一方是讀。 查看文檔 - 也許ConcurrentLinkedDeque將適合您。

實際上,這兩種解決方案都不夠。 實際上,您需要同步arraylist上的完整迭代,以及對arraylist的每次寫訪問:

synchronized(list) {
    for (T t : list) {
        ...
    }
}

synchronized(list) {
    // read/add/modify the list
}
  1. 使ArrayList易變。

你不能使ArrayList volatile 你不能使任何對象易變。 Java中唯一可以變化的東西是字段。

在您的示例中, list 不是 ArrayList

private static ArrayList<T> list;

listMain類的靜態字段

volatile關鍵字僅在一個線程更新字段時才起作用,另一個線程隨后訪問該字段。

該行更新列表 ,但更新揮發領域

list.add(e);

執行該行后,列表已更改,但該字段仍引用相同的列表對象。

暫無
暫無

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

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