多个生产者和多个消费者Java信号量阻塞队列

时间:2018-03-17 04:43:50

标签: java multithreading semaphore producer-consumer

我们正在尝试围绕信号量锁定队列执行多个生产者和多个使用者。我们遇到的问题是生产的产品多于我告诉它生产的产品。有人可以帮我弄清楚我们哪里出错了吗?感谢。

package prog2;

import java.util.Scanner;

public class prog2 {

public static void main(String[] args) throws Exception {

    Scanner scanner = new Scanner(System.in);
    System.out.println("Input number of producers threads, number of consumer threads, size of the buffer, and the number of items to be produced.");
    System.out.println("Format Ex: 4 5 10 1000");
    String input = scanner.nextLine();
    String[] numbers = input.split(" ");

    int num_producers, num_consumers, size_buffer, num_items, num_consumed, num_produced;
    num_producers = Integer.parseInt(numbers[0]);
    num_consumers = Integer.parseInt(numbers[1]);
    size_buffer = Integer.parseInt(numbers[2]);
    num_items = Integer.parseInt(numbers[3]);

    ProducerConsumer implementation = new ProducerConsumer(size_buffer, num_items);

    for(int producer_count = 0; producer_count < num_producers; producer_count++){ //creating multiple producers
                Producer p = new Producer(implementation);
                p.start();
    }

    for(int consumer_count = 0; consumer_count < num_consumers; consumer_count++){ //creating multiple consumers
                Consumer c = new Consumer (implementation);
                c.start();
    } 

    System.out.println("Number of Produced items: " + implementation.num_produced + " Number of Consumed items: " + implementation.num_consumed);

    }
}


package prog2;

public class Producer extends Thread{

protected ProducerConsumer implementation;

public Producer (ProducerConsumer implementation){
    this.implementation = implementation;
}

@Override
public void run(){
        try{ 
            while(implementation.done_processing != true){
                implementation.put();
            }
        }catch(InterruptedException e){
        }
}  
}

package prog2;

public class Consumer extends Thread{

protected ProducerConsumer implementation;

public Consumer (ProducerConsumer implementation){
    this.implementation = implementation;
}
  @Override
  public void run(){
    try{ 
        while(implementation.done_consuming != true){
            implementation.get();
        }
    }catch(InterruptedException e){
    }
}  
}


package prog2;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;

class ProducerConsumer {
//Queue Creation
private final BlockingQueue<Integer> queue = new LinkedBlockingQueue<>();
private final Random theRandom = new Random();
//Semaphore Creation
static Semaphore semProd = new Semaphore(1);
static Semaphore semCon = new Semaphore(0);

public boolean done_processing = false;
public boolean done_consuming = false;
public int num_items = 0;
private int size_buffer = 0;
public int num_produced = 0;
public int num_consumed = 0;

public ProducerConsumer (int size_buffer, int num_items){
    this.size_buffer = size_buffer;
    this.num_items = num_items;
}

public void write_producer_log (String data) throws IOException{
    File f1 = new File ("producer-event.log");
    if(!f1.exists()){
        f1.createNewFile();
    }
    FileWriter fileWriter = new FileWriter(f1.getName(),true);
    try (BufferedWriter bw = new BufferedWriter(fileWriter)) {
        bw.write(data);
        bw.newLine();
    }
}

public void write_consumer_log (String data) throws IOException{
    File f1 = new File ("consumer-event.log");
    if(!f1.exists()){
        f1.createNewFile();
    }
    FileWriter fileWriter = new FileWriter(f1.getName(),true);
    try (BufferedWriter bw = new BufferedWriter(fileWriter)) {
        bw.write(data);
        bw.newLine();
    }
}

public void put() throws InterruptedException {
    semProd.acquire();
    try {
        if(num_produced >= num_items){
            done_processing = true;
        }
            if (queue.size() == size_buffer) {
                return;
            }

            int number = theRandom.nextInt();
            boolean isAdded = queue.add(number);
            num_produced++;
                Timestamp timestamp = new Timestamp(System.nanoTime());
                String log_entry = timestamp + " Producer " +  
Thread.currentThread().getId() + " " + num_produced + " " + number +"\n";
              try{  
                write_producer_log(log_entry);
              }catch (IOException e){

              }
    } 
    finally {
            semCon.release();
    }

}

public void get() throws InterruptedException {
    semCon.acquire();
    try {
        if(num_consumed >= num_items){
            done_consuming = true;
        }
            if (queue.isEmpty()) {
                return;
            }

            Integer value = queue.take();
            num_consumed++;
                Timestamp timestamp = new Timestamp(System.nanoTime());
                String log_entry = timestamp + " Consumer " +  
Thread.currentThread().getId() + " " + num_consumed + " " + value +"\n";
              try{  
                write_consumer_log(log_entry);
              }catch (IOException e){

              }     
    } 
    finally {
        semProd.release();
    }
}
}

1 个答案:

答案 0 :(得分:0)

在课程prog2中,您应该使用thread.join等待所有制作人和消费者完成工作,然后才能打印num_producednum_consumed

public class prog2 {

    public static void main(String[] args) throws Exception {

        Scanner scanner = new Scanner(System.in);
        System.out.println("Input number of producers threads, number of consumer threads, size of the buffer, and the number of items to be produced.");
        System.out.println("Format Ex: 4 5 10 1000");
        String input = scanner.nextLine();
        String[] numbers = input.split(" ");

        int num_producers, num_consumers, size_buffer, num_items, num_consumed, num_produced;
        num_producers = Integer.parseInt(numbers[0]);
        num_consumers = Integer.parseInt(numbers[1]);
        size_buffer = Integer.parseInt(numbers[2]);
        num_items = Integer.parseInt(numbers[3]);

        ProducerConsumer implementation = new ProducerConsumer(size_buffer, num_items);
        Producer[] producers = new Producer[num_producers];
        Consumer[] consumers = new Consumer[num_consumers];

        for (int producer_count = 0; producer_count < num_producers; producer_count++) { //creating multiple producers
            producers[producer_count] = new Producer(implementation);
            producers[producer_count].start();
        }

        for (int consumer_count = 0; consumer_count < num_consumers; consumer_count++) { //creating multiple consumers
            consumers[consumer_count] = new Consumer(implementation);
            consumers[consumer_count].start();
        }

        for (int producer_count = 0; producer_count < num_producers; producer_count++) {
            producers[producer_count].join();
        }

        for (int consumer_count = 0; consumer_count < num_consumers; consumer_count++) {
            consumers[consumer_count].join();
        }

        System.out.println("Number of Produced items: " + implementation.num_produced + 
                " Number of Consumed items: " + implementation.num_consumed);
    }
}

在课程ProducerConsumer中,

  1. 您应该使用关键字volatile声明下面的变量,所以 读者线程始终可以获得更新的值:

    • done_processing
    • done_consuming
    • num_produced
    • num_consumed
  2. 您应该使用Semaphore.tryAcquire(long timeout, TimeUnit unit)代替 Semaphore.acquire(),这将阻止线程被阻塞 done_consuming = truedone_processing = true
  3. returndone_consuming = true时,您应立即done_processing = true ProducerConsumer,而是继续执行。
  4. 以下是import java.util.Random; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; class ProducerConsumer { //Queue Creation private final BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(); private final Random theRandom = new Random(); //Semaphore Creation static Semaphore semProd = new Semaphore(1); static Semaphore semCon = new Semaphore(0); public volatile boolean done_processing = false; public volatile boolean done_consuming = false; public int num_items = 0; private int size_buffer = 0; public volatile int num_produced = 0; public volatile int num_consumed = 0; public ProducerConsumer(int size_buffer, int num_items) { this.size_buffer = size_buffer; this.num_items = num_items; } public void put() throws InterruptedException { if (semProd.tryAcquire(100, TimeUnit.MILLISECONDS)) { try { if (num_produced >= num_items) { done_processing = true; return; } if (queue.size() == size_buffer) { return; } int number = theRandom.nextInt(); boolean isAdded = queue.add(number); num_produced++; } finally { semCon.release(); } } } public void get() throws InterruptedException { if (semCon.tryAcquire(100, TimeUnit.MILLISECONDS)) { try { if (num_consumed >= num_items) { done_consuming = true; return; } if (queue.isEmpty()) { return; } Integer value = queue.take(); num_consumed++; } finally { semProd.release(); } } } } 没有日志的代码:

    Input number of producers threads, number of consumer threads, size of the buffer, and the number of items to be produced.
    Format Ex: 4 5 10 1000
    4 5 10 1000
    Number of Produced items: 1000 Number of Consumed items: 1000
    
    Input number of producers threads, number of consumer threads, size of the buffer, and the number of items to be produced.
    Format Ex: 4 5 10 1000
    10 20 30 10000
    Number of Produced items: 10000 Number of Consumed items: 10000
    

    测试结果:

    {
        "word": "go",
        "synonyms": [
            "proceed",
            "run",
            "depart",
            "go away",
            "function",
            ...,
            "get",
            "plump",
            "extend",
            "fit"
        ]
    }