Ruby并发实现:多线程访问共享资源及内存级电影座位预订方案
Ruby并发与共享资源处理
1. Ruby中实现并发及共享资源处理
Ruby中实现并发最常用的方式是使用线程(Thread),处理多线程访问共享资源的核心是通过同步机制避免竞态条件。常见的同步工具包括:
- Mutex(互斥锁):最基础的同步原语,同一时间只允许一个线程持有锁进入临界区。
- Monitor:Ruby的
Object类默认混入MonitorMixin,可直接用mon_synchronize方法封装互斥锁逻辑。 - ConditionVariable:配合锁使用,用于线程间的等待/通知场景。
示例:用Mutex保护共享计数器
require 'thread' counter = 0 mutex = Mutex.new 10.times.map do Thread.new do 1000.times do mutex.synchronize do counter += 1 end end end end.each(&:join) puts counter # 稳定输出10000,无竞态条件
2. 内存实现电影座位预订及应用层校验
内存数据结构实现方案
用Hash存储座位状态(键为座位号,值为true已预订/false可预订),配合Mutex确保线程安全的读写操作,避免多个线程同时修改同一座位状态。
完整示例代码
require 'thread' class MovieSeatBooking def initialize(total_seats = 100) @seats = (1..total_seats).to_h { |num| [num, false] } @mutex = Mutex.new end # 预订座位,返回是否成功 def book_seat(seat_number) @mutex.synchronize do return false unless @seats.key?(seat_number) && !@seats[seat_number] @seats[seat_number] = true true end end # 查询座位状态 def seat_available?(seat_number) @mutex.synchronize do @seats.key?(seat_number) && !@seats[seat_number] end end end # 模拟并发预订测试 booking_system = MovieSeatBooking.new(10) 20.times.map do Thread.new do seat = rand(1..10) success = booking_system.book_seat(seat) puts "线程#{Thread.current.object_id}预订座位#{seat}:#{success ? '成功' : '失败(已被预订/不存在)'}" end end.each(&:join)
其他应用层校验方式
除了基于互斥锁的悲观锁方式,还可以使用:
- 乐观锁(版本号机制):给每个座位绑定版本号,预订时先读取当前版本号和座位状态,修改前校验版本号是否一致,一致则更新版本号和座位状态,否则重试。
class OptimisticMovieBooking def initialize(total_seats = 100) @seats = (1..total_seats).to_h { |num| [num, { available: true, version: 0 }] } @mutex = Mutex.new # 确保版本号与状态更新的原子性 end def book_seat(seat_number) @mutex.synchronize do seat = @seats[seat_number] return false unless seat && seat[:available] current_version = seat[:version] seat[:available] = false seat[:version] = current_version + 1 true end end end - CAS(比较并交换)操作:借助
atomicgem提供的原子变量,对座位状态或版本号进行原子更新,减少显式锁的使用。复杂场景下仍需结合逻辑校验,确保预订操作的正确性。
内容的提问来源于stack exchange,提问作者shubham saxena
相关产品推荐
相关产品推荐

