如何在 Java 中使数组线程安全?

问题描述 投票:0回答:1

我对多线程还很陌生,想更好地理解它。我现在想知道如何在 Java 中使数组线程安全?这意味着我有多个线程访问和更改数组中的数据,并且我想防止一个线程更改数据,而另一个线程正在读取数据。

我的方法如下: 我有一个 Data 类,其中包含一个数组和两个方法 updateData(Integer[] data)getUpdate() 用于访问和操作数组。

public class  Data <T extends Comparable> {
    private T[] data;

    public T[] getUpdate() {
        synchronized (this) {
            return data.clone();
        }
    }

    public void updateData(T[] data) {
        synchronized (this) {
            this.data = data.clone();
        }
    }
}

该数据对象现在在两个不同的线程中使用,主线程更新数据,swing EDT 线程读取数据并使用它。

public static void main(String[] args) {
    Data<Integer> data = new Data<>();
    data.updateData(new Integer[]{1,2,3,4,5,6,7,8,10});


    SwingUtilities.invokeLater(() -> {
        ColumnVisualizer visualizer = new ColumnVisualizer();

        new Timer(100, e -> {
            visualizer.setData(data.getUpdate());
        }).start();
    });
    
    while(condition) {
        data.updateData(createNewData());

    }
}

据我了解,如果我仅通过 updateData()getUpdate() 方法访问数组(我使用同步关键字使其成为线程安全的),那么数据本身就是线程安全的。因为如果一个线程调用 getUpdate() 方法,它会在 Data 实例上设置一个锁,并且当另一个线程想要调用 updateData() 时,它无法访问旧数组被新数组替换的部分,直到不再查看数据实例。

我是否理解正确?这是在 Java 中使数组线程安全的便捷方法吗?

java arrays multithreading thread-safety thread-synchronization
1个回答
0
投票

您的理解是正确的。 Data 实例将被阻止,直到同步块在您拥有的任一方法(getUpdate/updateData)中完成为止。

不过,根据您的代码,我对您有一些观察,这可能对您有用。 假设在时间戳 time1,一个线程(我们称之为 th1)到来并调用 getUpdate 并获取数据的克隆。假设一毫秒后(或更早)另一个线程(我们称之为 I th2)从同一方法 getUpdate 获取克隆数据。 假设4毫秒后,进程th1使用updateData更新数据,1毫秒后,进程th2调用相同的方法。 让我们看看这两个进程发生了什么:在调用 th2 的 updateData 之后,数据表将包含 th2 放置在那里的任何内容,完全忽略 1 毫秒前放置在那里的内容。 这是你想要的吗 ?我并不是说这是错误的,我只是说如果 2 个进程几乎同时使用该表(相差 1 毫秒或更小),就会发生这种情况。 如果您想要的是在 th2 的末尾数据表包含 th1 和 th2 的信息,您可能需要不同的方法。 例如。锁定进程的表,或使用方法类 Data 添加/删除表中的条目,而不将整个表交给进程来更新它....

© www.soinside.com 2019 - 2024. All rights reserved.