34-结果分析
结果分析
本案例实现了 MyPriorityTransferQueue 数据结构。这是一个用于生产者/消费者问题的数据结构,但其元素按优先级来排列,而不是顺序排列。由于Java不允许有多重继承,因此所做的第一个决定与 MyPriorityTransferQueue 类的基类有关。扩展该类以使用 PriorityBlockingQueue 中实现的操作,而不是单纯地实现它们。还实现了 Transfer Queue 接口来添加与生产者/消费者相关的方法。之所以做出这个选择,是因为我们认为实现 TransferQueue 接口的方法比 PriorityBlockingQueue 类中实现的方法更容易。但是,也可以实现从 LinkedTransferQueue 类上扩展而来的类,并实现必要的方法来获取自己的 PriorityBlockingQueue 类的版本。
MyPriortyTransferQueue 类具有以下3个字段。
- 一个
AtomicInteger类型的counter字段:该字段存储在数据结构中等待获取元素的消费者的数量。当消费者调用take()操作从数据结构中获取元素时,计数值会递增。当消费者执行完成take()操作时,计数值再次递减。该计数器用于实现hasWaitingConsumer()和getWaitingConsumerCount()方法。 - 一个
ReentrantLock类型的lock字段:该字段用于控制对已实现操作的访问,而且只允许一个线程处理数据结构。 - 最后一个
LinkedBlockingQueue列表来存储传输的元素。
我们在 MyPriorityTransferQueue 中实现了一些方法。所有方法都在 Transfer Queue 接口中声明,并且 take() 方法在 PriorityBlockingQueue 接口中实现。这两个都在前面已描述过,以下是对其余方法的描述。
tryTransfer(E e):该方法尝试直接向消费者发送元素。如果消费者正在等待,则它将该元素存储在消费者立即消费的优先级队列中,然后返回true;如果没有消费者在等待,则返回false。transfer(E e):该方法直接将一个元素传递给消费者。如果有消费者在等待,则它将该元素存储在优先级队列中以供消费者立即使用;否则,该元素将存储在传输元素的列表中,并且该线程将会阻塞,直到使用元素。当线程进入休眠状态时,必须释放锁,因为如果不这样做,将会阻塞队列。tryTransfer(E e,long timeout,TimeUnit unit):该方法与transfer()方法相似,但此处线程会阻塞由其参数确定的时间段。当线程进入休眠状态时,必须释放锁,因为如果不这样做,会阻塞队列。take():该方法返回要使用的下一个元素。如果传输元素的列表中有元素,则从列表中取出该元素。否则,它将从优先队列中取出。
一旦实现了该数据结构,就要实现 Event 类。它是存储在数据结构中的元素的类。 Event 类有两个字段来存储生产者ID和事件优先级,并且它实现了 Comparable 接口,因为这是该数据结构的一个要求。
然后,实现生产者和消费者类。在这个例子中,有10个生产者和1个消费者,它们共享相同的缓冲区。每个生产者生成100个具有递增优先级的事件,因此具有较高优先级的事件是最后生成的。
本案例的主类创建了一个 MyPriorityTransferQueue 对象、10个生产者和1个消费者,并使用 MyPriorityTransferQueue 缓冲区中的 transfer() 方法将两个事件传递到缓冲区。
下图显示了该程序执行的一部分输出内容。
可以看到具有更高优先级的事件是如何首先被消费的,并且消费者是如何消费传递事件的。