Does ruby have the Java equivalent of synchronize keyword? Does ruby have the Java equivalent of synchronize keyword? multithreading multithreading

Does ruby have the Java equivalent of synchronize keyword?


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  endendc = Counter.newt1 = Thread.new { 100_000.times { c.tick } }t2 = Thread.new { 100_000.times { c.tick } }t1.join; t2.joinc.count → 200000


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 rubyrequire '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 }"  endendc = Counter.new3.times.map do |i|  Thread.new do       c.tick i  endend.each(&:join)puts c.count

In the output you will get sometihing like that:

before (1): 0after (1): 1before (2): 0before (0): 0 <- !!after (2): 2after (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 rubyrequire '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  endendc = Counter.new3.times.map do |i|  Thread.new do       c.tick i  endend.each(&:join)puts c.count

Output:

before (1): 0after (1): 1before (0): 1after (0): 2before (2): 2after (2): 3Total: 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.