13

ruby には synchronize キーワードに相当する Java がありますか? 私は 1.9.1 を使用していますが、これを行うエレガントな方法がよくわかりません。

4

2 に答える 2

16

キーワードはありませんが、クラスsynchronizeを介して非常によく似たものを取得できます。Monitor以下は、プログラミング Ruby 1.8 ブックの例です。

require 'monitor'

class Counter < Monitor
  attr_reader :count
  def initialize
    @count = 0
    super
  end

  def tick
    synchronize do
      @count += 1
    end
  end
end

c = Counter.new
t1 = Thread.new { 100_000.times { c.tick } }
t2 = Thread.new { 100_000.times { c.tick } }
t1.join; t2.join
c.count → 200000
于 2010-07-08T22:32:59.657 に答える
14

受け入れられた答えは、どのように機能するかを表していませんsynchronize!

コメントアウトしてsynchronize do、受け入れられた回答のスクリプトを実行するだけです-出力は同じになります: 200_000!

synchronizeしたがって、ブロックあり/なしの実行の違いを示す例を次に示します。

スレッドセーフではない例:

#! /usr/bin/env ruby

require 'monitor'

class Counter < Monitor
  attr_reader :count
  def initialize
    @count = 0
    super
  end

  def tick i
    puts "before (#{ i }): #{ @count }"
    @count += 1
    puts "after (#{ i }): #{ @count }"
  end
end

c = Counter.new

3.times.map do |i|
  Thread.new do
       c.tick i
  end
end.each(&:join)
puts c.count

出力では、次のようなものが得られます。

before (1): 0
after (1): 1
before (2): 0
before (0): 0 <- !!
after (2): 2
after (0): 3 <- !!
Total: 3

スレッド(0)が開始されたとき、countは と等しかった0が、追加後+1の値は でした3

そこで何が起こるの?

スレッドが開始されると、初期値の が表示されcountます。しかし、それぞれを加算しようとする+1と、並列計算の結果、値が異なってしまいました。適切な同期がないと、 の部分的な状態countは予測できません。

原子性

これらの操作をアトミックと呼びます:

#! /usr/bin/env ruby

require 'monitor'

class Counter < Monitor
  attr_reader :count
  def initialize
    @count = 0
    super
  end

  def tick i
    synchronize do
      puts "before (#{ i }): #{ @count }"
      @count += 1
      puts "after (#{ i }): #{ @count }"
    end
  end
end

c = Counter.new

3.times.map do |i|
  Thread.new do
       c.tick i
  end
end.each(&:join)
puts c.count

出力:

before (1): 0
after (1): 1
before (0): 1
after (0): 2
before (2): 2
after (2): 3
Total: 3

ここで、synchronizeブロックを使用して、追加操作の原子性を確保します。

ただし、スレッドは引き続きランダムな順序で実行されます (1->0->2)

詳細な説明については、この記事を読み続けることができます。

于 2015-06-15T08:14:42.840 に答える