临界资源,类似上面说的管程的概念,这个类在实现时用了一个对象数组,当然也可以用LinkedList来做,更为方便。来分析一个put方法。刚开始使用到一个之前提到的循环锁,循环条件是(tail + 1) % buffer.length == head,这里用到了数据结构中的循环队列,故判断循环队列满的条件如上,如果满了,自然只能等待,一旦有一个空位,则将消息放入空位,同时将队尾指针加一,最后唤醒所有等待的线程。比较简单,却十分核心。
|
生产者类,主要产生消息,注意继承了Thread并实现了run,并且有一个对MessageQueue实例的引用,主要调用了MessageQueue的put方法。
消费者类,主要消费消息,跟生产者是对称的,主要调用了MessageQueue的get方法。
主类,主要构造出一个MessageQueue并启动N个生产者和消费者。
从以上这个例子,可以看出来,通过一个MessageQueue,我们将一个对象的创建和执行分离开了(在生产者中创建,在消费者中执行,注意,这个对象可以执行复杂的方法)。这种分离带来了极大的好处。比如将费时的执行分开之后提高了创建线程的响应性,并且它们之间的顺序实现了可控性,不用创建完了马上就执行;同时我们能够创建后根据条件取消或者重复执行;最后它们的分离使得可以分布式做创建和分离,从而出现了类似BMQ的消息中间件。
最后来讲一个JDK中Producer-Consumer的应用,提起JAVA的多线程,最先想到的自然是JVM后台执行的那个GC(garbage collection)始终默默无闻的执行清扫工作,甚至让我们感觉不到;其次是applet,每个applet都要继承Applet,而Applet的init就是创建线程的方法;最后,最为常用的一个就是JAVA的GUI了,为了保证GUI的响应性,JAVA使用了多线程,并且是用生产者消费者问题来解决问题的。