看到几个关于有界缓冲区的在线示例。对他们的实施不满意。我对Java比较新。对改进版本有什么好的建议或意见吗?谢谢。 例如:
import com.google.common.collect.Lists;
import java.util.List;
public class BoundedBufferNotGood {
private final List<Integer> data;
private final int capacity;
private int size;
private int head;
private int tail;
BoundedBufferNotGood(int capacity) {
this.data = Lists.newArrayListWithCapacity(capacity);
this.capacity = capacity;
size = 0;
head = 0;
tail = 0;
}
public synchronized void put(Integer x) throws InterruptedException {
while (size == capacity) wait();
data.add(head, x);
head++;
head %= capacity;
size++;
notifyAll();
}
public synchronized Integer get() throws InterruptedException {
while (size == 0) wait();
Integer x = data.get(tail);
tail++;
tail %= capacity;
size--;
notifyAll();
return x;
}
}
此代码可以正常工作,但在不必要的睡眠和唤醒方面非常糟糕。 put()中的wait()函数和get()等待这个。但他们应该等待不同的。在get()方法中,wait()应该等待大小&gt; 0,put()应该等待大小&lt;容量。
改进版本:
import com.google.common.collect.Lists;
import java.util.List;
public class BoundedBuffer {
private final List<Integer> data;
private final int capacity;
private int size;
private int head;
private int tail;
private final Object dataCV = new Object();
private final Object spaceCV = new Object();
BoundedBuffer(int capacity) {
this.data = Lists.newArrayListWithCapacity(capacity);
this.capacity = capacity;
size = 0;
head = 0;
tail = 0;
}
public synchronized void put(Integer x) throws InterruptedException {
while (size == capacity) {
synchronized (spaceCV) { // do we need to move synchronized() outside of while loop?
wait();
}
}
data.add(head, x);
head++;
head %= capacity;
size++;
dataCV.notifyAll();
}
public synchronized Integer get() throws InterruptedException {
while (size == 0) {
synchronized (dataCV) {
wait();
}
}
Integer x = data.get(tail);
tail++;
tail %= capacity;
size--;
spaceCV.notifyAll();
return x;
}
}
答案 0 :(得分:1)
put()中的wait()函数和get()在相同条件下等待
使用java.util.concurrent.locks.ReentrantLock
代替synchronized
。
ReentrantLock
的优点是你可以从同一个锁对象中获得两个(或更多)条件变量,因此你可以让一个条件让生产者等待,并为消费者提供不同的条件,但每个人锁定相同的锁。
使用
Lock myLock = new ReentrantLock();
创建锁定对象,然后使用
Condition producerCondition = myLock.newCondition();
Condition consumerCondition = myLock.newCondition();
创建两个条件变量。
然后你可以使用:
myLock.lock(); //instead of entering a synchronized block,
myLock.unlock(); //instead of leaving the synchronized block,
consumerCondition.await(); // instead of this.wait();
consumerCondition.signal(); // instead of this.notifyAll();
等
提示:使用try { ... } finally { ... }
确保锁定已解锁。
答案 1 :(得分:0)
感谢大家。使用Condition的新版本。
import com.google.common.collect.Lists;
import net.jcip.annotations.GuardedBy;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class BoundedBuffer {
@GuardedBy("lock”) private final List<Integer> data;
@GuardedBy("lock”) private final int capacity;
@GuardedBy("lock") private int size;
@GuardedBy("lock”) private int head;
@GuardedBy("lock”) private int tail;
Lock lock = new ReentrantLock();
private final Condition spaceCondition = lock.newCondition();
private final Condition dataCondition = lock.newCondition();
BoundedBuffer(int capacity) {
this.data = Lists.newArrayListWithCapacity(capacity);
this.capacity = capacity;
size = 0;
head = 0;
tail = 0;
}
public void put(int x) throws InterruptedException {
lock.lock();
try {
while (size == capacity) {
spaceCondition.await();
}
data.add(head, x);
head++;
head %= capacity;
size++;
dataCondition.signalAll();
} finally {
lock.unlock();
}
}
public int get() throws InterruptedException {
lock.lock();
try {
while (size == 0) {
dataCondition.await();
}
int x = data.get(tail);
tail++;
tail %= capacity;
size--;
spaceCondition.signalAll();
return x;
} finally {
lock.unlock();
}
}
}