数组列表上的 java 易失性/同步 [英] java Volatile/synchronization on arraylist

查看:49
本文介绍了数组列表上的 java 易失性/同步的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的程序是这样的:

public class Main {
    private static ArrayList<T> list;

    public static void main(String[] args) {
        new DataListener().start();
        new DataUpdater().start();
    }

    static class DataListener extends Thread {
        @Override
        public void run() {
            while(true){
                //Reading the ArrayList and displaying the updated data
                Thread.sleep(5000);
            }
        }
    }

    static class DataUpdater extends Thread{
        @Override
        public void run() {
            //Continuously receive data and update ArrayList;
        }
    }
}

为了在两个线程中都使用这个ArrayList,我知道两个选项:

In order to use this ArrayList in both threads, I know two options:

  1. 使 ArrayList 可变.但是我在 这篇文章 中读到,使变量可变是仅当它写入变量不依赖于其当前值"时才允许.我认为在这种情况下确实如此(因为例如,当您对 ArrayList 执行添加操作时,此操作后 ArrayList 的内容取决于 ArrayList 的当前内容,或者不是吗?).此外,DataUpdater 必须不时从列表中删除一些元素,而且我还了解到无法从不同线程编辑易失性变量.

  1. To make the ArrayList volatile. However I read in this article that making variables volatile is only allowed if it "Writes to the variable do not depend on its current value." which I think in this case it does (because for example when you do an add operation on an ArrayList, the contents of the ArrayList after this operation depend on the current contents of the ArrayList, or doesn't it?). Also the DataUpdater has to remove some elements from the list every now and then, and I also read that editing a volatile variable from different threads is not possible.

使这个 ArrayList 成为一个同步变量.但是,我的 DataUpdater 会不断更新 ArrayList,所以这不会阻止 DataListener 读取 ArrayList 吗?

To make this ArrayList a synchronized variable. However, my DataUpdater will continuously update the ArrayList, so won't this block the DataListener from reading the ArrayList?

我是否误解了此处的任何概念,或者是否有其他选择可以使这成为可能?

Did I misunderstand any concepts here or is there another option to make this possible?

推荐答案

Volatile 根本不会帮助你.volatile 的含义是线程 A 对共享变量所做的更改对线程 B 立即可见.通常,此类更改可能位于某些缓存中,仅对创建它们的线程可见,而 volatile 只是告诉 JVM 不要进行任何会导致值更新延迟的缓存或优化.

Volatile won't help you at all. The meaning of volatile is that changes made by thread A to a shared variable are visible to thread B immediately. Usually such changes may be in some cache visible only to the thread that made them, and volatile just tells the JVM not to do any caching or optimization that will result in the value update being delayed.

所以它不是一种同步方式.这只是确保变更可见性的一种手段.此外,它更改的是变量,而不是该变量引用的对象.也就是说,如果您将 list 标记为 volatile,则只有在您将新列表分配给 list,不是如果你改变列表的内容!

So it is not a means of synchronization. It's just a means of ensuring visibility of change. Moreover, it's change to the variable, not to the object referenced by that variable. That is, if you mark list as volatile, it will only make any difference if you assign a new list to list, not if you change the content of the list!

您的另一个建议是使 ArrayList 成为同步变量.这里有一个误解.变量不能同步.唯一可以同步的是代码 - 整个方法或其中的特定块.您使用一个对象作为同步监视器.

Your other suggestion was to make the ArrayList a synchronized variable. There is a misconception here. Variables can't be synchronized. The only thing that can be synchronized is code - either an entire method or a specific block inside it. You use an object as the synchronization monitor.

监视器是对象本身(实际上,它是监视器对象的逻辑部分),而不是变量.如果您在同步旧值后将不同的对象分配给同一变量,那么您将无法使用旧监视器.

The monitor is the object itself (actually, it's a logical part of the object that is the monitor), not the variable. If you assign a different object to the same variable after synchronizing on the old value, then you won't have your old monitor available.

但无论如何,同步的不是对象,而是您决定使用该对象同步的代码.

But in any case, it's not the object that's synchronized, it's code that you decided to synchronize using that object.

因此,您可以使用 list 作为同步操作的监视器.但是你不能让 list 同步.

You can therefore use the list as the monitor for synchronizing the operations on it. But you can not have list synchronized.

假设您想使用列表作为监视器来同步您的操作,您应该设计它以便编写器线程不会一直持有锁.也就是说,它只是为单个读取更新、插入等获取它,然后释放它.为下一次操作再次抓取它,然后释放它.如果同步整个方法或整个更新循环,其他线程将永远无法读取它.

Suppose you want to synchronize your operations using the list as a monitor, you should design it so that the writer thread doesn't hold the lock all the time. That is, it just grabs it for a single read-update, insert, etc., and then releases it. Grabs it again for the next operation, then releases it. If you synchronize the whole method or the whole update loop, the other thread will never be able to read it.

在阅读线程中,您可能应该执行以下操作:

In the reading thread, you should probably do something like:

List<T> listCopy;

synchronized (list) {
    listCopy = new ArrayList(list);
}

// Use listCopy for displaying the value rather than list

这是因为显示可能很慢 - 它可能涉及 I/O、更新 GUI 等.所以为了最小化锁定时间,您只需从列表中复制值,然后释放监视器,以便更新线程可以执行它的工作.

This is because displaying is potentially slow - it may involve I/O, updating GUI etc. So to minimize the lock time, you just copy the values from the list, and then release the monitor so that the updating thread can do its work.

除此之外,java.util.concurrent 包等中有许多类型的对象,旨在帮助处理这样的情况,其中一侧正在写入,另一侧正在读取.检查文档 - 也许 ConcurrentLinkedDeque 对你有用.

Other than that, there are many types of objects in the java.util.concurrent package etc. that are designed to help in situations like this, where one side is writing and the other is reading. Check the documentation - perhaps a ConcurrentLinkedDeque will work for you.

这篇关于数组列表上的 java 易失性/同步的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆