不使用wait关键字同步块是否安全?

时间:2011-07-26 17:00:01

标签: java multithreading wait notify

我有一个线程使用值填充矢量对象,另一个线程定期从中获取值并定期清除它。

我希望访问该向量的任一线程在另一个访问它时暂停。我是否需要使用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

5 个答案:

答案 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方法的值是,使用者线程(读取数据的那个)不必经常轮询,而是当向量达到某个时,生成器线程可以通知它。大小