我有一个线程使用值填充矢量对象,另一个线程定期从中获取值并定期清除它。
我希望访问该向量的任一线程在另一个访问它时暂停。我是否需要使用wait / notify / notifyAll关键字?
private Vector<Long> _recordIdsSent;
# Called by main thread (before thread A and thread B are started)
public ConstructorOfThisClass() {
_recordIdsSent = new Vector<Long>();
// Starts thread A & B
}
# Called by thread A
public void addSentRecordIds( List<Long> ids ) {
synchronized (_recordIdsSent) {
_recordIdsSent.addAll( ids );
}
}
# Called by thread B
public void deleteRecords()
{
List<Long> ids;
synchronized (_recordIdsSent) {
ids = (List<Long>) _recordIdsSent.clone();
_recordIdsSent.clear();
}
// Delete the records matching ids....
}
注意:我克隆了_recordIdsSent向量,因为删除操作可能需要一些时间。
[编辑] 将synchronized关键字从方法签名移动到变量_recordIdsSent
答案 0 :(得分:4)
你不必。只需将同步块放在addSentRecordIds
中,就像deleteRecords
一样。
因此,您一次只能访问Vector一个线程。
答案 1 :(得分:1)
如前所述,在提供的代码中,addSentRecordIds
向量的访问权限未同步 - 这会使您的代码不安全
此外,此代码段不保证用于锁定的对象(_recordIdsSent
)不会更改 - 这也使得不安全。我自己通常更喜欢专用的锁定对象,因为它使我的意图更清晰,更不容易出错。像这样:
private final Object lock = new Object(); // dedicated lock object
//... _recordIdsSent, addSentRecordIds etc...
public void deleteRecords()
{
List<Long> ids;
synchronized (lock) {
ids = (List<Long>) _recordIdsSent.clone();
_recordIdsSent.clear();
}
// Delete the records matching ids....
}
答案 2 :(得分:1)
这不是原始问题的答案,而是对解决手头问题的不同方法的建议。
您可以使用单个线程池(java.util.concurrent):
Executor executor = Executors.newSingleThreadExecutor();
当你想写/删除数据库时:
executor.call(new Runnable() {
@Override public void run() { ... write to DB}
});
executor.call(new Runnable() {
@Override public void run() { ... delete in DB}
});
无论你在哪里调用它们,它们都会在同一个线程中运行。
编辑:来自newSingleThreadExecutor的javadoc: “创建一个Executor,它使用一个工作线程来操作一个无界的队列。(但是请注意,如果这个单线程由于在关闭之前执行期间的故障而终止,那么如果需要执行后续任务,新的将会取代它。)任务保证按顺序执行,并且在任何给定时间都不会有多个任务处于活动状态。与其他等效的newFixedThreadPool(1)不同,保证返回的执行程序不能重新配置为使用其他线程。“答案 3 :(得分:0)
您不必因为synchronized关键字正在为您执行此操作。
同步意味着一次只能有一个线程在该块中,或者该类中的任何其他同步块。这意味着如果类中有两个不同的对象需要是线程安全的,并且您将这两个不同对象的操作方法设置为synchronized,那么访问其中一个对象的线程将阻止其他线程访问另一个对象(不理想),所以不要过度使用它,否则你将抵消多线程的所有好处。
答案 4 :(得分:0)
如前面的帖子中所述,在修改数据结构的方法上使用synchronized关键字将阻止并发访问和潜在的数据损坏。
使用wait和notify方法的值是,使用者线程(读取数据的那个)不必经常轮询,而是当向量达到某个时,生成器线程可以通知它。大小