通过同步了解生产者/消费者关系

时间:2017-06-29 19:56:48

标签: java multithreading exception producer-consumer

我需要同时创建一个动态数字(我从命令行获取),这将是消费者和另一个将成为生产者的线程。

这些线程有共享缓冲区,生产者将随机数写入10次,但我必须确保在下一次他将编写时,只有当所有消费者都读取生产者的数据时写道,任何消费者只读一次

消费者报告他们阅读的当前价值。

我使用了一个布尔数组,其大小与我得到的数字相同,所以在第一次读取消费者时,我将数组中的值更改为true。

当我运行它时,我得到一个java.lang.IllegalMonitorStateException,我不明白为什么......

生产者根本没有写入缓冲区。

感谢。

Buffer.java

public interface Buffer
{
    public void set(int value) throws InterruptedException;

    public int get() throws InterruptedException;

    public boolean areAllTrue();

    public void markedRead(int index);

    public boolean checkInedx(int index);

    public void setAllFalse();
}

SynchronizedBuffer.java

import java.util.Arrays;

// Fig. 23.18: SynchronizedBuffer.java
// Synchronizing access to shared data using Object 
// methods wait and notify.
public class SynchronizedBuffer implements Buffer
{
    private int buffer = -1; // shared by producer and consumer threads
    private boolean occupied = false; // whether the buffer is occupied
    private boolean[] flags;

    public SynchronizedBuffer(int n)
    {
        this.flags = new boolean[n];
    }

    public synchronized void markedRead(int index)
    {
        this.flags[index] = true;
    }

    public synchronized boolean checkInedx(int index)
    {
        return flags[index];
    }

    public synchronized boolean areAllTrue()
    {
        for (boolean b : flags)
            if (!b)
                return false;
        return true;
    }

    public synchronized void setAllFalse()
    {
        Arrays.fill(flags, false);
    }

    // place value into buffer
    public synchronized void set(int value) throws InterruptedException
    {
        // while there are no empty locations, place thread in waiting state
        while (occupied)
        {
            // output thread information and buffer information, then wait
            System.out.println("Producer tries to write.");
            displayState("Buffer full. Producer waits.");
            wait();
        } // end while

        buffer = value; // set new buffer value

        // indicate producer cannot store another value
        // until consumer retrieves current buffer value
        occupied = true;

        displayState("Producer writes " + buffer);

        notifyAll(); // tell waiting thread(s) to enter runnable state
    } // end method set; releases lock on SynchronizedBuffer

    // return value from buffer
    public synchronized int get() throws InterruptedException
    {
        // while no data to read, place thread in waiting state
        while (!occupied)
        {
            // output thread information and buffer information, then wait
            System.out.println("Consumer tries to read.");
            displayState("Buffer empty. Consumer waits.");
            wait();
        } // end while
            // indicate that producer can store another value
            // because consumer just retrieved buffer value
        occupied = false;

        displayState("Consumer reads " + buffer);

        notifyAll(); // tell waiting thread(s) to enter runnable state

        return buffer;
    } // end method get; releases lock on SynchronizedBuffer

    // display current operation and buffer state
    public void displayState(String operation)
    {
        System.out.printf("%-40s%d\t\t%b\n\n", operation, buffer, occupied);
    } // end method displayState
} // end class SynchronizedBuffer

Producer.java

// Fig. 23.12: Producer.java
// Producer with a run method that inserts the values 1 to 10 in buffer.
//import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

public class Producer implements Runnable
{
    // private final static Random generator = new Random();
    private final Buffer sharedLocation; // reference to shared object
    private int count;

    // constructor
    public Producer(Buffer shared)
    {
        sharedLocation = shared;
    } // end Producer constructor

    // store randomly values from 1 to 100 in sharedLocation
    public void run()
    {
        int sum = 0;
        try
        {
            while (!sharedLocation.areAllTrue())
            {
                wait();
            }
            Thread.sleep(ThreadLocalRandom.current().nextLong(3000l));
            count = ThreadLocalRandom.current().nextInt(1, 101);
            sharedLocation.set(count); // set value in buffer
            sharedLocation.setAllFalse();
            notifyAll();
            sum += count; // increment sum of values
            System.out.printf("\t%2d\n", sum);
        } // end try


        catch (InterruptedException exception)
        {
            exception.printStackTrace();
        } // end catch

        System.out.println("Producer done producing\nTerminating Producer");
    } // end method run
} // end class Producer

Consumer.java

import java.util.concurrent.ThreadLocalRandom;

// Fig. 23.13: Consumer.java
// Consumer with a run method that loops, reading 10 values from buffer.

public class Consumer implements Runnable
{
    private final Buffer sharedLocation; // reference to shared object
    private final int index;

    // constructor
    public Consumer(Buffer shared, int index)
    {
        sharedLocation = shared;
        this.index = index;
    } // end Consumer constructor

    // read sharedLocation's value 10 times and sum the values
    public void run()
    {
        int sum = 0;
        for (int count = 1; count <= 10; count++)
        {
            // sleep 0 to 3 seconds, read value from buffer and add to sum
            try
            {
                while (sharedLocation.checkInedx(index))
                {
                    wait(); // wait until 
                }
                Thread.sleep(ThreadLocalRandom.current().nextLong(3000l));
                sum += sharedLocation.get();
                sharedLocation.markedRead(this.index);
                System.out.printf("\t\t\t%2d\n", sum);
                notifyAll();
            } // end try

            catch (InterruptedException exception)
            {
                exception.printStackTrace();
            } // end catch
        } // end for

        System.out.printf("\n%s %d\n%s\n", "Consumer read values totaling", sum, "Terminating Consumer");
    } // end method run
} // end class Consumer

ConsumerNProducers.java

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ConsumerNProducers
{

    public static void main(String[] args) throws InterruptedException
    {
        // create a newCachedThreadPool
        ExecutorService application = Executors.newCachedThreadPool();

        // create SynchronizedBuffer to store ints
        Buffer sharedLocation = new SynchronizedBuffer(Integer.parseInt(args[0]));

        System.out.printf("%-40s%s\t\t%s\n%-40s%s\n\n", "Operation", "Buffer", "Occupied", "---------", "------\t\t--------");

        // execute the Producer and Consumer tasks
        application.execute(new Producer(sharedLocation));
//      Thread.sleep(5000);
        for (int i = 0; i < Integer.parseInt(args[0]); i++)
        {
            application.execute(new Consumer(sharedLocation, i));
        }
        application.shutdown();

    } // end main

}

1 个答案:

答案 0 :(得分:0)

您的制作人正在等待这种情况产生:

while (!sharedLocation.areAllTrue())

因此,如果您的所有生产者从一开始就在等待,sharedLocation中的所有条目都不是true,而且它们似乎永远不会被初始化。我建议您更改构造函数,以便初始化所有值:

public SynchronizedBuffer(int n)
{
    this.flags = new boolean[n];
    Arrays.fill(flags, true);
}