我有一个循环缓冲区(数组/先出先出),消费者和生产者。生产者将随机数放入数组中,消费者获取第一个数字并检查它是否是相对素数。
我的代码有效,我认为它可以正常工作,但我想改进它。 我不太确定我的“无效运行”方法。我是否应该在其他地方进行异常处理?改变“无限循环”?不应更改方法签名(它们是预定义的)。
我很乐意改进代码的每个建议。 (不关心可见性(公共,......)和静态事物,我只是把它放在一个文件中。
import java.math.BigInteger;
import java.util.Random;
public class ConsProd {
static class CircularBuffer {
private BigInteger[] buffer;
//"pointers"
private int read;
private int write;
public CircularBuffer(int size) {
this.buffer = new BigInteger[size];
this.read = 0;
this.write = 0;
}
public boolean isFull() {
for(int i = 0; i < buffer.length; i++) {
if(buffer[i] == null)
return false;
}
return true;
}
public boolean isEmpty() {
for(int i = 0; i < buffer.length; i++) {
if(buffer[i] != null)
return false;
}
return true;
}
public synchronized void put(BigInteger element) throws InterruptedException {
while(isFull()){
wait();
}
buffer[write] = element;
write = (write+1)%buffer.length;
notifyAll();
}
public synchronized BigInteger take() throws InterruptedException {
while(isEmpty()){
wait();
}
BigInteger temp = buffer[read];
buffer[read] = null;
read = (read+1)%buffer.length;
notifyAll();
return temp;
}
}
static class Consumer implements Runnable {
private int id;
private CircularBuffer buffer;
public Consumer(int id, CircularBuffer b) {
this.id = id;
this.buffer = b;
}
private void consume(BigInteger e) {
synchronized(e){
System.out.println("consumer " + id + " retrieved: " + e);
if (e.isProbablePrime(100)) {
System.out.println(" -----> probably prime!");
}
}
}
@Override
public void run() {
try { // TODO is this the right place to handle the exception?
while (!Thread.currentThread().isInterrupted()) {
BigInteger e = buffer.take();
consume(e);
}
} catch (InterruptedException e) { }
}
}
static class Producer implements Runnable {
private int id;
private CircularBuffer buffer;
public Producer(int id, CircularBuffer b) {
this.id = id;
this.buffer = b;
}
protected BigInteger produce() {
BigInteger x = new BigInteger(10, new Random());
System.out.println("producer " + id + " produced: " + x.toString());
return x;
}
@Override
public void run() {
try { // TODO is this the right place to handle the exception?
while (!Thread.currentThread().isInterrupted()) {
BigInteger e = produce();
buffer.put(e);
}
} catch (InterruptedException e) { }
}
}
public static void main(String[] args) {
CircularBuffer cbuf = new CircularBuffer(4);
Thread t1 = new Thread(new Consumer(1, cbuf));
Thread t2 = new Thread(new Consumer(2, cbuf));
Thread t3 = new Thread(new Consumer(3, cbuf));
Thread t4 = new Thread(new Producer(1, cbuf));
Thread t5 = new Thread(new Producer(2, cbuf));
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
答案 0 :(得分:0)
这是旧的,但我想我会喜欢的。将来,codereview.stackexchange.com的问题似乎更好。
对于改进代码的每条建议,我都会感到高兴。
我的第一个回答是,您应该使用ExecutorService
而不是Consumer
线程和循环。生产者可以保留您编写的内容,尽管我怀疑拥有多线程功能会对您有所帮助。您的e.isProbablePrime()
方法比new BigInteger(10, new Random());
慢许多数量级。
由于生产者和消费者之间的速度差异,您必须使用有限的ExecutorService
创建BlockingQueue
。类似于以下内容:
threadPool = new ThreadPoolExecutor(2, 2, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(100));
然后,当您的制作人创建BigInteger
时,它将执行以下操作:
threadPool.put(new Consumer(randomBigInteger());
您的消费者将根本没有循环。这将负责线程,共享缓冲区和所有同步代码。您无需进行管理。尽管您还可以提交Callable<?>
并使用Future<?>
来获取结果,但是您将需要自己恢复所有结果。
如果您不能使用ExecutorService
的东西,那么尽管我会使用LinkedBlockingQueue
而不是您的CircularBuffer
,但是您的代码看起来还不错。