熟悉线程的朋友应该对经典的售票员卖票程序不陌生。全国各地有很多售票点同时发售车票,车票在这里作为一个公用的资源,各地的售票中心访问资源,打印车票给顾客。我们来看一下ruby实现这个简单功能的代码吧:
# 线程-买票实例 class Ticket attr_reader :ticket attr_reader :value def initialize @ticket = %w(a b c d e f g h i j k l m n o p q r s t u v w x y z) @value = 0 end def buy_ticket @k = @ticket if @k.empty? puts "no result" @value +=1 else sleep(3*rand) puts "the ticket is #{@k.last} " sleep(3*rand) @value +=1 puts "OK #{@value}" @ticket.pop puts "**************分隔符******************" end end end a = Ticket.new t1 = Thread.new { 10.times {puts "线程1" ; a.buy_ticket } } t2 = Thread.new { 10.times { puts "线程2"; a.buy_ticket } } t3 = Thread.new { 10.times { puts "线程3"; a.buy_ticket } } t1.join t2.join t3.join我们开了3个线程分别表示不同的3个售票点同事发售车票,我们在发售车票的时候使用了sleep来模拟工作人员操作的时间。
@ticket = %w(a b c d e f g h i j k l m n o p q r s t u v w x y z)@ticket这个数组用来表示一组车票。好我们来运行这个程序,看能看到什么结果
线程1线程2线程3 the ticket is z OK 1 **************分隔符****************** 线程3 the ticket is y the ticket is y the ticket is y OK 2 **************分隔符****************** 线程2 OK 3 **************分隔符****************** 线程1 OK 4 **************分隔符****************** 线程3 the ticket is v the ticket is v the ticket is v OK 5我们可以看见,有的车票被多个窗口同时卖出,当然这在规定当中是不允许的。这个是为什么呢?我们来看一下程序。乍一看是肯定没有什么问题的。细细想想,假设我们的线程1进入卖票程序,并查看到当前可以买y票。线程1睡眠一段时间,假设这段时间正好线程2进来了,并执行了卖票程序,此时线程1并未实际意义上的把票卖了出去,这就导致了两个线程卖出了同一张票。
那么有没有解决办法呢?比如说,在线程1进入程序的时候,就把票给锁死了,这样线程2来的时候就不能对该张票进行操作。在ruby当中有个监视器monitor可是实现该功能。我们对买票这个操作进行监视控制,只能同时一个人来操作。好吧,我们来看一下下面的代码:
# 线程-买票实例 require 'monitor' class Ticket attr_reader :ticket attr_reader :value def initialize @ticket = %w(a b c d e f g h i j k l m n o p q r s t u v w x y z) @value = 0 end def buy_ticket @k = @ticket if @k.empty? puts "no result" @value +=1 else sleep(3*rand) puts "the ticket is #{@k.last} " sleep(3*rand) @value +=1 puts "OK #{@value}" @ticket.pop puts "**************分隔符******************" end end end a = Ticket.new k = Monitor.new t1 = Thread.new { 10.times {k.synchronize{puts "线程1" ; a.buy_ticket }} } t2 = Thread.new { 10.times {k.synchronize{puts "线程2" ; a.buy_ticket }} } t3 = Thread.new { 10.times {k.synchronize{puts "线程3" ; a.buy_ticket }} } t1.join t2.join t3.join puts a.value我们使用了监视器来对资源进行监视,不能同时由多个线程进行操作,避免重复卖票的情况,这中间的核心部分就是如下所示:
k = Monitor.new t1 = Thread.new { 10.times {k.synchronize{puts "线程1" ; a.buy_ticket }} } t2 = Thread.new { 10.times {k.synchronize{puts "线程2" ; a.buy_ticket }} } t3 = Thread.new { 10.times {k.synchronize{puts "线程3" ; a.buy_ticket }} }
当然,我们可以不对该操作进行监视,我们对票据资源进行监视。也会使用到synchronize。这里就不再赘述,想知道的可以参考programming ruby。
好拉。今天就写这么多吧。o(∩_∩)o...哈哈