我做了一个生产者 - 消费者计划。它只是核心java中没有任何GUI(Swing或SWT)的程序。它有一个将对象放入队列的生产者。 还有一些消费者必须将一些人员(例如String)添加到该共享队列中的每个对象中。因此,每个使用者必须处理共享队列中的每个对象。 在这种情况下 - 每个BookShelf必须包含来自“books”ArrayList中所有使用者的项目。消费者。
问题:我应该在消费者中使用什么条件才能正确完成线程? 以下是该程序的代码片段。也许我用错误的方式实现了它。
以下是队列的对象:
public class BookShelf {
private int id;
private String name;
private int height;
private int weigh;
List<String> books = Collections.synchronizedList(new ArrayList<String>());
public BookShelf(int id, String name) {
this.id = id;
this.name = name;
}
public void addBook(String book) {
books.add(book);
}
public boolean eq(String book) {
synchronized (books) {
for (String b: books) {
if (b.equalsIgnoreCase(book)) {
return true;
}
}
}
return false;
}
other setters and getters..
}
这是生产者类:
public class Producer implements Runnable {
private BlockingQueue myQueue;
public Producer(BlockingQueue myQueue) {
this.myQueue = myQueue;
}
public void run() {
for(int i=0; i<7; i++){
try {
System.out.println("Produced: " + i);
BookShelf myBookShelf = new BookShelf(i, "book #" + i);
myQueue.put(myBookShelf);
} catch (InterruptedException ex) {
//Proper handle
}
}
}
}
以下是消费者类别之一:
public class Consumer implements Runnable {
private BlockingQueue myQueue;
public Consumer(BlockingQueue myQueue) {
this.myQueue = myQueue; }
public void run() {
while(true){
try {
BookShelf tempBookShelf = (BookShelf) myQueue.take();
//eq() is my method to check if ArraList has a book.
if (tempBookShelf.eq("Abc book")) {
System.out.println("It already has book");
myQueue.put(tempBookShelf);
Thread.sleep(2000);
} else {
tempBookShelf.addBook("Abc book");
myQueue.put(tempBookShelf);
Thread.sleep(2000);
}
} catch (InterruptedException ex) {
//Proper handle
}
}
}
}
这是主要课程:
public class ProducerConsumerTest {
public static void main(String[] args) {
BlockingQueue sharedQueue = new LinkedBlockingQueue();
Thread prodThread = new Thread(new Producer(sharedQueue));
Thread consThread = new Thread(new Consumer(sharedQueue));
Thread consThread2 = new Thread(new Consumer2(sharedQueue));
prodThread.start();
consThread.start();
consThread2.start();
}
}
答案 0 :(得分:1)
向生产者注册每个消费者。每个使用者都有自己的队列,生产者将对象放入所有队列。然后,每个使用者处理对象的同一实例。
public interface Consumer{
public void process(BookShelf bs);
}
public class Producer implements Runnable{
private final List<Consumer> consumers = new CopyOnWriteArrayList<Consumer>(); // thread safe but not efficient with lots of changes
public void register(Consumer c){
consumers.add(c); // thread safe
}
public void run(){
for(;;){
BookShelf bs = generateBookShelfByWhateverMeans();
for (Consumer c : consumers){
c.process(bs);
}
}
}
}
public class BookShelfConsumer implements Runnable, Consumer{
private final BlockingQueue<BookShelf> queue = new LinkedTransferQueue<BookShelf>(); // unbounded & thread safe
public void process(BookShelf bs){
queue.offer(bs); // non-blocking
}
public void run(){
for(;;){
BookShelf bs = queue.take(); // blocks until got object or interrupted
// catch InterruptedException
// do whatever this consumer is supposed to do with the object
}
}
}
答案 1 :(得分:0)
我会尝试使用SwingWorker代替。它有一个done()
方法,在完成后执行。有关一些代码示例,请参阅this页面。
如果你使用的不是Swing,Swt中有一个类似的函数叫做Jobs。查看this页面以获取示例。它还有一个在工作完成时执行的done()方法。
答案 2 :(得分:0)
还有一些(N个)消费者必须在该共享队列中的每个对象中添加一些人员(例如String)
我认为你的意思是每个消费者都必须将他们的东西添加到每个进入队列的对象中。在这种情况下,这是不生产者 - 消费者问题,这更像是观察者可观察到的问题。基本上,当创建新BookShelf
时,即Observable。所有Observers都应该收到有关BookShelf
的通知,并有机会添加自己的Book
。
答案 3 :(得分:0)
我建议在Bookshelf中使用ConcurrentLinkedQueue而不是同步列表 - 它是无锁的(不需要同步),并且可能更有效。
要结束您的消费者,请将他们的while(true)
循环更改为while(!cancel)
循环。为每个使用者提供一个cancel
布尔值作为初始化为false的实例变量,并为它们提供一个cancel()
方法,将cancel
设置为true。完成后,请与您的消费者联系cancel()
。如果您要一次取消所有消费者(而不是有选择地取消某些消费者而不取消其他消费者),那么您可以使用静态cancel
而不是实例cancel
。