当使用Java线程原语构造线程安全的有界队列时-这两种构造有什么区别
- 创建显式锁对象。
- 使用列表作为锁并等待。
1
示例private final Object lock = new Object();
private ArrayList<String> list = new ArrayList<String>();
public String dequeue() {
synchronized (lock) {
while (list.size() == 0) {
lock.wait();
}
String value = list.remove(0);
lock.notifyAll();
return value;
}
}
public void enqueue(String value) {
synchronized (lock) {
while (list.size() == maxSize) {
lock.wait();
}
list.add(value);
lock.notifyAll();
}
}
2
示例private ArrayList<String> list = new ArrayList<String>();
public String dequeue() {
synchronized (list) { // lock on list
while (list.size() == 0) {
list.wait(); // wait on list
}
String value = list.remove(0);
list.notifyAll();
return value;
}
}
public void enqueue(String value) {
synchronized (list) { // lock on list
while (list.size() == maxSize) {
list.wait(); // wait on list
}
list.add(value);
list.notifyAll();
}
}
注意
- 这是一个有界列表
- 没有其他操作正在执行,除了进入队列和退出队列。
- 我可以使用阻塞队列,但这个问题更多的是为了提高我有限的线程知识。 如果这个问题是重复的,请让我知道。
简短的回答是,不,除了维护额外锁对象的额外内存开销之外,没有功能上的区别。然而,在做出最终决定之前,我要考虑几个与语义相关的项目。
我是否需要执行同步操作,而不仅仅是我的内部列表?
假设您想要维护一个与ArrayList
并行的数据结构,这样列表上的所有操作和并行数据结构都需要同步。在这种情况下,最好使用外部锁,因为列表或结构上的锁可能会对该类的未来开发工作造成混淆。
我是否会在我的队列类之外访问我的列表?
假设您想为列表提供一个访问器方法,或者使其对Queue类的扩展可见。如果使用外部锁对象,则检索到列表引用的类将永远无法对该列表执行线程安全操作。在这种情况下,最好在列表上同步,并在API中明确对列表的外部访问/修改也必须在该列表上同步。
我相信你会选择其中一个而不是另一个,但这是我能想到的两个最大的原因。