2014-10-09 184 views
0

如果我創建一個類變量,像這樣:類變量和初始化時間

class Song 
    @@plays = 0 

    class << self 

    def plays=(plays) 
     @@plays += plays 
    end 

    def plays 
     @@plays 
    end 

    end 

end 

的我有多個線程訪問這個類的方法和JRuby中設置它:

t1 = Thread.new {st1 = Song.plays = 1} 
t2 = Thread.new {st2 = Song.plays = 5} 
t3 = Thread.new {st3 = Song.plays = 3} 

是否有可能有2個線程同時初始化@@播放到0?在執行的哪個階段是創建類變量?

+0

您的代碼不適合工作我。沒有'Song#plays =',而是在'Song'的singleton類中創建這個方法作爲類方法。 – Stefan 2014-10-09 11:23:34

+0

修正了它,我習慣性地添加了新的。 – 2014-10-09 11:33:24

+1

不,仍然不起作用。 'Song.singleton_class.plays ='可以工作,但這可能不是你想要的。 – Stefan 2014-10-09 11:35:05

回答

2

@@plays = 0在Ruby評估您的類定義時設置。這應該只發生一次,然後開始你的線程。

另一方面,分配方法plays=可以同時執行。因此,你應該把它包在一個synchronize調用,如:

require 'thread' 
require 'song' # <- @@plays is set to 0 here 

Song.plays #=> 0 

semaphore = Mutex.new 

t1 = Thread.new { semaphore.synchronize { Song.plays = 1 } } 
t2 = Thread.new { semaphore.synchronize { Song.plays = 5 } } 
t3 = Thread.new { semaphore.synchronize { Song.plays = 3 } } 

[t1, t2, t3].each(&:join) 
Song.plays #=> 9 

另一種選擇是讓Song#plays=線程安全的互斥體移動到Song類:

class Song 
    @@plays = 0 
    @@semaphore = Mutex.new 

    def self.plays=(plays) 
    @@semaphore.synchronize { @@plays += plays } 
    end 

    # ... 
end 
+0

我應該在類變量中創建互斥鎖以確保它不是由2個線程同時創建的嗎?同樣的問題措詞不同,你如何讓宋課程安全? – 2014-10-09 12:12:36

+0

@KieranAndrews是的,像'@@ plays'一樣創建互斥體,即在開始線程之前。 – Stefan 2014-10-09 12:15:59

+1

@KieranAndrews我已經更新了我的答案。 – Stefan 2014-10-09 12:19:28