这里用java多线程实现一个简单的抽奖程序,从100个座位号中,随机抽取10位。
我设计的思路是用10个线程,每个线程从100个座位号中随机抽取1位,然后显示在黑板上,然后再去抽取,再显示。这里涉及到从100 个座位号中随机抽取时要线程之间要同步,否则会出现同一个号被多个线程抽取。一个线程大致分为如下几个步骤:
a.从待抽取的座位列表中随机抽取座位。
b.将抽取的座位号显示在黑板对应的位置上,并取得那个位置上当前显示的座位号。
c.将b步得到的座位号添加到待抽取列表中。
经过a,b,c三步,一个线程一次的动作算完成了,将这三步操作视为一个原子操作,进行线程间同步,剩下的就是循环抽取座位号就行了。
有几点需求注意:
1.b步可以不同步,但发现,当随机抽取的数量多时,此时一个线程(假设代号为1)还没有来得及更新黑板上对应位置的座位号,另一个线程(假设代号为2)已经将1线程放入座位组中的号又取出来,并显示在黑板上了。这样就会造成黑板上同一个座位号显示了多次。
2.需要区分哪些座位号是抽取过的,哪些座位号是没有抽取过的,这样每次抽取只抽取没有抽取过的。会自然而然的用两个List表示。但仔细想想,不需要用两个List区分,因为黑板上显示的座位号就是已经抽取的,只需要每次从座位池中删除,然后显示在黑板上,再次抽取时,将黑板上原来显示的座位号放回座位池中即可。
3.是否可以用LinkedList代替ArrayList。大家都知道LinkedList的删除,插入性能优于ArrayList,并且这里线程也需要反复不断的对座位池进行删除,新增操作。但这里的新增只是在最后面加入,影响不大,有影响的就是删除操作。但是这样还会有不断的随机取号操作。到底是删除操作影响大,还是取号操作影响大呢?经过验证发现,当座位池中座位号比较大时(假如为10万),LinkedList速度会明显慢于ArrayList,几乎有10倍之差。
源码如下:
抽取号码部分:
1 | package cn.yanggy.demo03; |
屏幕部分:
1 | package cn.yanggy.demo03; |
本文的目的是线程的运用,所以屏幕部分写的比较简陋。其中要注意的是线程的暂停和恢复,需要同步的对象是线程本身,即synchronized (this){wait();},否则会报异常:java.lang.IllegalMonitorStateException
v1.5.2