Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does ruby have the Java equivalent of synchronize keyword?

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.

like image 871
Zombies Avatar asked Jul 08 '10 22:07

Zombies


People also ask

What is a synchronized keyword in Java?

The synchronized Keyword. When we use a synchronized block, internally Java uses a monitor also known as monitor lock or intrinsic lock, to provide synchronization. These monitors are bound to an object, thus all synchronized blocks of the same object can have only one thread executing them at the same time.

How do you synchronize a method in Ruby?

In Java we can make a method 'synchronized' by just using the 'synchronized' keyword in the function definition. How do we do it in Ruby? Show activity on this post. Synchronize keyword is not present in Ruby. Alternatively just can just wrap the method call to Mutex (i.e. fancy word for Lock).

How many levels can the synchronized keyword be used on?

The synchronized keyword can be used on different levels: 1 Instance methods 2 Static methods 3 Code blocks

What happens when we use synchronized keyword with a static method?

When we use a synchronized keyword with a static method, the lock is acquired in the class. In synchronized static methods only one thread can execute inside a static synchronized method in the same class.


2 Answers

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
like image 117
Chris Bunch Avatar answered Oct 15 '22 21:10

Chris Bunch


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.

like image 43
skywinder Avatar answered Oct 15 '22 20:10

skywinder