简体   繁体   English

在不使用wait关键字的情况下同步块是否安全?

[英]Is it safe to synchronize a block without using the wait keyword?

I have one thread populating a vector object with values, and one other thread that periodically fetches the values from it and clears it periodically. 我有一个线程用值填充矢量对象,另一个线程定期从中获取值并定期清除它。

I want that either thread accessing the vector pauses while the other one is accessing it. 我希望其中一个访问向量的线程都暂停,而另一个正在访问它。 Do I need to use the wait/notify/notifyAll keywords ? 我是否需要使用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....
}

Note: I clone the _recordIdsSent vector because the delete operation can take some time. 注意:我克隆_recordIdsSent向量,因为删除操作可能需要一些时间。

[EDIT] Moved the synchronized keyword from the method signature to the variable _recordIdsSent [EDIT]将同步关键字从方法签名移至变量_recordIdsSent

You dont have to. 您不必。 Just put a synchronized block in addSentRecordIds just like deleteRecords . 只需将一个同步块放入addSentRecordIds ,就像deleteRecords一样。 So, you will only access your Vector one thread at a time. 因此,您一次只能访问Vector一个线程。

As already noted, in provided code access to vector from addSentRecordIds is not synchronized - that makes your code unsafe 如前所述,在提供的代码中,从addSentRecordIds对vector的访问不同步-这使您的代码不安全

Also, this code snippet does not guarantee that object used for locking ( _recordIdsSent ) doesn't change - this makes it unsafe too. 另外,此代码段不能保证用于锁定( _recordIdsSent )的对象不会更改-这也使其不安全 Myself I typically prefer dedicated objects for locking because it makes my intent cleaner and is less error prone. 我本人通常更喜欢使用专用对象进行锁定,因为这可以使我的意图更清晰并且更不易出错。 Like this: 像这样:

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....
}

This is not an answer to the original question, but a suggestion on a different way of tackling the problem at hand. 这不是对原始问题的答案,而是对解决当前问题的另一种建议。

You could use a single thread pool (java.util.concurrent): 您可以使用一个线程池(java.util.concurrent):

Executor executor = Executors.newSingleThreadExecutor();

and when you want to write/delete to the DB: 当您想写入/删除数据库时:

executor.call(new Runnable() {
   @Override public void run() { ... write to DB}
});

executor.call(new Runnable() {
   @Override public void run() { ... delete in DB}
});

Wherever you call those, they'll run in the same thread. 无论您在何处调用它们,它们都将在同一线程中运行。

EDIT: from the javadoc of newSingleThreadExecutor: "Creates an Executor that uses a single worker thread operating off an unbounded queue. (Note however that if this single thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks.) Tasks are guaranteed to execute sequentially, and no more than one task will be active at any given time. Unlike the otherwise equivalent newFixedThreadPool(1) the returned executor is guaranteed not to be reconfigurable to use additional threads." 编辑:来自newSingleThreadExecutor的javadoc:“创建一个执行程序,该执行程序使用在不受限制的队列上运行的单个工作线程。(但是请注意,如果该单个线程由于在执行关闭之前的执行期间失败而终止,则将替换一个新线程确保任务按顺序执行,并且在任何给定时间都不会激活多个任务。与其他等效的newFixedThreadPool(1)不同,保证返回的执行程序不可重新配置为使用其他线程“。

You don't have to as the synchronized keyword is doing that for you. 您不必这样做,因为synced关键字正在为您完成此任务。

Synchronized means that only one thread can be in that block, or any other synchronized block in the class, at a time. 同步意味着一次只能有一个线程在该块或该类中的任何其他同步块中。 This means that if the class has two distinct objects in it that need to be thread safe, and you make the methods that manipulate both of those distinct objects as synchronized, then a thread accessing one of the objects will block other threads from accessing the other object (not ideal), so don't overuse it or you'll counteract all the benefits of having multithreading. 这意味着,如果该类中有两个需要线程安全的不同对象,并且使操作这两个不同对象的方法处于同步状态,则访问其中一个对象的线程将阻止其他线程访问另一对象对象(不理想),所以不要过度使用它,否则您将抵消使用多线程的所有好处。

As noted in the earlier posts, using the synchronized keyword on the methods modifying your data structure will prevent concurrent access and potential corruption of your data. 如之前的文章所述,在修改数据结构的方法上使用synced关键字将防止并发访问和潜在的数据损坏。

The value in using wait and notify methods is that the consumer thread (the one reading the data) doesn't have to constantly poll, rather it can be notified by the producer thread(s) when the vector has reached a certain size. 使用wait和notify方法的价值在于,使用者线程(读取数据的线程)不必不断轮询,而是可以在向量达到一定大小时由生产者线程通知。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM