Home How to Write Thread-Safe Ruby Code

How to Write Thread-Safe Ruby Code

Thread safety means your code behaves correctly even when multiple threads run at the same time. In MRI Ruby, the GIL limits true parallel execution of Ruby bytecode, but thread safety still matters. Race conditions can happen whenever threads interleave around shared state.

The classic ||= pitfall

Using ||= for lazy initialization looks harmless, but it is not thread-safe. Two threads can observe @cache as nil and both compute the value.

class ReportBuilder
  def report
    @report ||= expensive_report
  end

  private

  def expensive_report
    sleep 1
    "report"
  end
end

If two threads call report together, you may compute twice or partially update shared state. This is a race condition.

Make ||= safe with a Mutex

Wrap the lazy initialization in a mutex and double-check the value inside the lock.

class ReportBuilder
  def initialize
    @report_lock = Mutex.new
  end

  def report
    return @report if @report

    @report_lock.synchronize do
      @report ||= expensive_report
    end
  end

  private

  def expensive_report
    sleep 1
    "report"
  end
end

This keeps the fast path cheap and makes the write safe.

A safer alternative: use Concurrent::Map

If you need a cache with multiple keys, use a thread-safe structure.

require "concurrent/map"

class PricingCache
  def initialize
    @cache = Concurrent::Map.new
  end

  def price_for(sku)
    @cache.compute_if_absent(sku) { expensive_lookup(sku) }
  end

  private

  def expensive_lookup(sku)
    sleep 1
    42
  end
end

Guidelines for thread-safe Ruby

  • Avoid shared mutable state when possible.
  • Protect writes with Mutex or use thread-safe collections.
  • Keep critical sections small.
  • Prefer immutability for shared objects.
  • Test race conditions with many threads.

Summary

Even with the GIL, Ruby code can hit race conditions. ||= is a common source of unsafe lazy initialization. Guard it with a mutex or use thread-safe data structures for shared caches.

References

Share this post

Comments