2016-11-10 74 views
0

我有兩個線程,每個線程都有自己的計數器:線程A有counterA,線程B有counterB。每個線程必須使用兩個計數器:線程A必須使用counterA和counterB,而線程B必須使用兩者。 我正在使用AtomicInteger並共享兩個線程之間的計數器,我將它們作爲參數傳遞給線程,並且每個線程將兩個計數器存儲在專用字段中。安全發佈,參數傳遞

// ... 
AtomicInteger counterA = new AtomicInteger(0); 
AtomicInteger counterB = new AtomicInteger(0); 

Thread tA = new Thread(new RunnableA(counterA, counterB)); 
Thread tB = new Thread(new RunnableB(counterA, counterB)); 

// ... in the constructor of RunnableA ... 
RunnableA(AtomicInteger counterA, AtomicInteger counterB) { 
    this.counterA = counterA; 
    this.counterB = counterB; 
} 

//... 
// The same for RunnableB 

這是兩個計數器的safe publishing? 安全發佈是必要的,因爲對對象的引用不夠安全,無法在線程之間共享對象。 如何在這種情況下實現安全發佈?

在此先感謝。

回答

1

術語「安全出版物」不適用於此。安全發佈是關於在構造函數中創建的狀態的發佈。在你的例子中,AtomicInteger對象是在構造函數被調用之前創建的。

如果使用了其他類型,根據是否以及如何發佈counterAcounterB變量,這可能安全也可能不安全。但是,通過將計數器實施爲AtomicInteger對象,您無需擔心發佈。它們是原子/線程安全的,不管它們是如何發佈的。只有可能關注可能是發佈實例變量的狀態。我們無法分辨出是否發生這種情況,而不去查看班上的其他人。例如:

  • 是變量finalvolatile
  • 如果它們是非易失性和非最終的,是否正確地訪問它們同步?
  • 是否在調用run()之後被線程限制?

注意,可運行將在當前線程被實例化,而不是在那些時候(如果)tA.start()tB.start()被稱爲創建的線程。當start()被調用時,有一個之前發生的當前線程的start()呼叫,新線程的run()調用之間。這意味着保證將變量安全地發佈到子線程本身。這只是將變量發佈給其他線程所關心的問題。

+0

「我不能馬上看到,可能是」 - 如果計數器被新創建的線程作爲的Runnable的實例變量的外部訪問。在構造函數中初始化的值在被訪問之前並不保證是可見的,除非例如聲明至少一個實例變量爲final,請參閱https://shipilev.net/blog/2014/safe-public-construction/ –

+0

好吧......但是在構造函數返回之前,這些變量怎麼能被* anything *訪問?查看構造函數的代碼。 (我知道安全發佈意味着什麼,'final'只是實現它的一種方法。) –

+0

「當start()被調用時,在當前線程的start()調用和新線程的run ()調用,這意味着保證將變量安全地發佈到子線程本身。「這是我覺得有用的一點。例如,儘管Runnable是在主線程中構建的,但是不需要在Runnable中聲明「參數變量」(this.counterA,this.counterB)作爲final,然後這些參數變量可以在創建的線程。 –