我需要同时创建一个动态数字(我从命令行获取),这将是消费者和另一个将成为生产者的线程。
这些线程有共享缓冲区,生产者将随机数写入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
}
答案 0 :(得分:0)
您的制作人正在等待这种情况产生:
while (!sharedLocation.areAllTrue())
因此,如果您的所有生产者从一开始就在等待,sharedLocation
中的所有条目都不是true
,而且它们似乎永远不会被初始化。我建议您更改构造函数,以便初始化所有值:
public SynchronizedBuffer(int n)
{
this.flags = new boolean[n];
Arrays.fill(flags, true);
}