[英]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,我知道兩個選項:
使ArrayList易變。 但是,我在本文中讀到,只有在“寫入變量不依賴於其當前值”時才允許變量volatile。 我認為在這種情況下它(因為例如當你對ArrayList執行添加操作時,此操作之后的ArrayList的內容取決於ArrayList的當前內容,或者不是嗎?)。 此外,DataUpdater必須時不時地從列表中刪除一些元素,我還讀到不可能從不同的線程編輯volatile變量。
使此ArrayList成為同步變量。 但是,我的DataUpdater會不斷更新ArrayList,所以這不會阻止DataListener讀取ArrayList嗎?
我是否誤解了這里的任何概念,還是有其他選擇使這成為可能嗎?
揮發性對你沒有任何幫助。 volatile
的含義是線程A對共享變量所做的更改立即對線程B可見。 通常這樣的更改可能在某些緩存中僅對構成它們的線程可見,而volatile
只是告訴JVM不要進行任何緩存或優化,這將導致值更新被延遲。
所以它不是一種同步手段。 這只是確保變革可見性的一種手段。 而且,它是變量的變化,而不是變量 引用的對象 。 也就是說,如果您標記list
為volatile
,只會讓任何區別,如果您分配一個新的列表, 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
}
- 使ArrayList易變。
你不能使ArrayList volatile
。 你不能使任何對象易變。 Java中唯一可以變化的東西是字段。
在您的示例中, list
不是 ArrayList
。
private static ArrayList<T> list;
list
是Main
類的靜態字段 。
volatile
關鍵字僅在一個線程更新字段時才起作用,另一個線程隨后訪問該字段。
該行更新列表 ,但不更新揮發領域 :
list.add(e);
執行該行后,列表已更改,但該字段仍引用相同的列表對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.