Does ruby have the Java equivalent of synchronize keyword?

风流意气都作罢 提交于 2019-12-18 03:22:28

问题


Does ruby have the Java equivalent of synchronize keyword? I am using 1.9.1 and I don't quite see an elegant way to do this.


回答1:


It doesn't have the synchronize keyword, but you can get something very similar via the Monitor class. Here's an example from the Programming Ruby 1.8 book:

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



回答2:


The accepted answer doesn't represent how synchronize works!

You can just comment out synchronize do and run accepted answer's script - output will be the same: 200_000!

So, here is an example, to show the difference between running with/without synchronize block:

Not thread safe example:

#! /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

In the output you will get sometihing like that:

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

When the thread (0) started, count was equal to 0, but after adding +1 its value was 3.

What happens here?

When the threads are starting they see the initial value of count. But when each of them, try to add +1, the value became different as result of the parallel computation. Without a proper synchronization, the partial state of count is unpredictable.

Atomicity

Now we call these operations atomic:

#! /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

Output:

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

Now, by using synchronize block, we ensure the atomicity of the add operation.

but threads still running in random order (1->0->2)

For detailed explanation, your can continue reading this article.



来源:https://stackoverflow.com/questions/3208462/does-ruby-have-the-java-equivalent-of-synchronize-keyword

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!