13

ruby 是否有 Java 等效的 synchronize 关键字?我正在使用 1.9.1,但我并没有看到一种优雅的方式来做到这一点。

4

2 回答 2

16

它没有synchronize关键字,但你可以通过类获得非常相似的东西Monitor。这是 Programming 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 回答