【问题标题】:Share an array between threads in java在java中的线程之间共享一个数组
【发布时间】:2022-01-23 07:08:55
【问题描述】:

我目前正在开发自己的小棋盘游戏,但遇到了多线程问题。我有一个渲染板的线程和一个提供要渲染的数据的线程。供应线程将他的数据写入一个数组,然后渲染器获取此数据并将其渲染到屏幕上(渲染线程从不向数组写入任何内容)。因此,我开始阅读有关线程之间的多线程和共享对象和数组以及数组上的 volatile 关键字的信息,并发现使数组 volatile 并不能解决问题。然后我读到了happens-before关系,有点困惑。 https://docs.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html#MemoryVisibility 这么说

监视器的解锁(同步块或方法退出)发生在同一监视器的每个后续锁定(同步块或方法入口)之前。并且由于happens-before关系是可传递的,因此线程在解锁之前的所有动作都发生在任何线程锁定该监视器之后的所有动作之前。

因此,如果我理解正确,我将不得不以同步方法对数组进行读写,所以在这段代码中,读取器总是拥有写入器写入数组的数据?

class Test {

    private static String[] data = new String[10];

    public synchronized String read(int index) {
        return data[index];
    }

    public synchronized void write(String value, int index) {
        data[index] = value;
    }

    private Thread writer = new Thread(() -> {
        while(true) {
            write("Test", 0);
            System.out.println("Wrote " + read(0) + " to 0.");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException exc) {
                //Handle exception
            }
        }
    });

    private Thread reader = new Thread(() -> {
        while(true) {
            System.out.println("Read " + read(0) + " from 0.");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException exc) {
                //Handle exception
            }
            //Render the data
    });

    public static void main(String[] args){
        writer.start();
        reader.start();
    }
}

谢谢。

PS。我不是母语人士,所以请原谅一些语法错误。

【问题讨论】:

  • 在 Internet 上搜索 java producer consumer 并阅读 Oracle 的 Java 教程中的 Concurrency 课程。你的writer 线程是生产者,你的reader 线程是消费者。

标签: java arrays multithreading


【解决方案1】:

AtomicReferenceArray 将为您提供您正在寻找的语义。非常有效,一个包含易失元素的数组。

在技术术语中,如果数组中某个元素的读取看到(相同元素的)写入,则读取将与该写入同步。所以在写和读之间会有一个happens-before边缘。

【讨论】:

  • AtomicReferenceArray 是否支持多维数组?
  • 没有。但是您可以通过将棋盘上的 x,y 坐标转换为数组中的位置来模拟多维数组的行为。
  • 或者我可以创建一个由字符串的 AtomicReferenceArrays 组成的 AtomicReferencArray。
  • 这也是一种选择。
【解决方案2】:

您可以尝试使用CopyOnWriteArrayList,但从您的描述看来,Queue 是最适合您需求的数据结构。您有一个数据生产者(您的供应商线程)和消费者(您的渲染器线程)。所以,看起来 Queue 真的给了你你需要的东西。阅读Queue接口,选择你需要的队列实现,可能是LinkedBlockingQueue

【讨论】:

  • 很好的建议,但不幸的是它们不符合我的需要。 CopyOnWriteArrayList 不起作用,因为它没有固定的元素限制,而 Queue 的问题是,我并不总是以相同的顺序访问元素,有时需要两次从元素获取信息。
  • 就顺序而言,是的,它始终按照元素放入队列的顺序提供元素,这就是队列的重点。但是如果你需要访问某些元素两次使用 ConcurrentHashMap
猜你喜欢
  • 1970-01-01
  • 2015-09-08
  • 1970-01-01
  • 2018-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-12
  • 1970-01-01
相关资源
最近更新 更多