类变量和初始化时间

时间:2014-10-09 10:57:31

标签: ruby thread-safety jruby

如果我像这样创建一个类变量:

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?在执行的哪个阶段创建了类变量?

1 个答案:

答案 0 :(得分:2)

Ruby评估您的类定义时设置

@@plays = 0。这应该只发生一次,然后才开始你的线程。

另一方面,分配方法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