java - 我是否需要同步访问仅由一个线程修改的列表?

标签 java multithreading paint thread-synchronization

这里我有一个类,它有两个可以访问列表的线程。一个线程定期用更新的副本替换列表,另一个线程将列表的内容绘制到屏幕上。

public class ThreadSafePainter {
    private List<String> dataList = new ArrayList<>();

    /*
     *  starts a thread to periodically update the dataList
     */
    public ThreadSafePainter() {
        Thread thread = new Thread(() -> {
            while (true) {
                // replace out-dated list with the updated data
                this.dataList = getUpdatedData();
                // wait a few seconds before updating again
                Thread.sleep(5000);
            }
        });
        thread.start();
    }

    /*
     *  called 10 times/second from a separate paint thread
     *  Q: Does access to dataList need to be synchronized?
     */
    public void onPaint(Graphics2D g) {
        Point p = new Point(20, 20);

        // iterate through the data and display it on-screen
        for (String data : dataList) {
            g.drawString(data, p.x, p.y);
            p.translate(0, 20);
        }
    }

    /*
     *  time consuming data retrieval
     */
    private List<String> getUpdatedData() {
        List<String> data = new ArrayList<>();
        // retrieve external data and populate list
        return data;
    }
}

我的问题是,我需要同步访问dataList吗?我应该怎么做?这行得通吗:

public ThreadSafePainter() {
    ...
            synchronized (this) {
                this.dataList = getUpdatedData();
            }
    ...
}

public void onPaint(Graphics2D g) {
    ...
    synchronized (this) {
        for (String data : dataList)
            ...
    }
}

最佳答案

任何时候你有多个线程访问同一个可变状态(好吧,几乎任何时候,都有一些异常(exception),比如当你知道状态不会在另一个线程的生命周期内发生变化时),你需要采取某些 类型的操作。在这种情况下,您正在改变字段 dataList 并且您希望另一个线程对此使用react。所以,你需要做“某事”。最通用的解决方案是使用 synchronized,您对如何执行此操作的概述很好。

如果你想从某些东西中获得最大性能(这对于 GUI 问题来说有点荒谬),或者你想炫耀你对并发的深刻理解,你可以考虑更多适用于更多应用的轻量级替代方案有限的情况。在这种情况下,您只有一位作者,而且作者只写了一篇引用文献。对于这种情况,volatile 就足够了。在这种代码中,我个人会坚持使用 synchronized,因为它不太可能在您更改代码时中断,例如您可能添加另一个编写器线程或其他内容。

关于java - 我是否需要同步访问仅由一个线程修改的列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33423744/

相关文章:

java - JFrame 中的绘画不起作用 (Java)

java - 如何使 JPA OneToOne 关系变得懒惰

java - 如何以编程方式调整 JTable 列的大小,DefaultTableModel Java

java - 在服务中同步执行长时间运行的方法

java - 用 Java 类 Android 画一条线

javascript - 检测所有 CSS 规则何时被应用和绘制

java - servlet 到 SQL Server 的许多连接,它们一起工作,导致 javaw.exe 过度上升

java - Java SSL TrustManager 上的部分链验证

multithreading - 多线程冒泡排序。在 delphi 7 上可以正常工作,但在 Lazarus 上却不行?编译器错误?

Python:使用守护线程一段时间后终止多线程程序