【问题标题】:Recieving updates from a thread(other than the EDT) in a Swing based application在基于 Swing 的应用程序中从线程(REST 除外)接收更新
【发布时间】:2015-03-06 05:46:08
【问题描述】:

这个问题是关于 volatile 关键字的用法。我有一个显示表格的摇摆应用程序,并且有一个单独的线程将行添加到表格模型中。根据this,似乎我必须将一些字段标记为易失性,以确保 EDT 看到对表模型所做的更新。但即使没有使列表不稳定,更新似乎也有效。以下是我的代码

import java.awt.BorderLayout;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        JFrame frame = new JFrame("FrameDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        MyTableModel dm = new MyTableModel();
        frame.getContentPane().add(new JScrollPane(new JTable(dm)), BorderLayout.CENTER);

        new Thread(new Runnable() {
            int count = 0;

            @Override
            public void run() {
                while (true) {
                    dm.addElement(count++);
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        frame.pack();
        frame.setVisible(true);
    }

    class Row {
        private String name;
        private String value;

        public Row(String name, String value) {
            super();
            this.name = name;
            this.value = value;
        }

    }

    class MyTableModel extends AbstractTableModel {
        private List<Row> rows = new ArrayList<Test.Row>();

        @Override
        public int getRowCount() {
            return rows.size();
        }

        @Override
        public int getColumnCount() {
            return 2;
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            if (columnIndex == 0) {
                return rows.get(rowIndex).name;
            } else if (columnIndex == 1) {
                return rows.get(rowIndex).value;
            } else {
                throw new IllegalArgumentException();
            }
        }

        private void addElement(int i) {
            rows.add(new Row("Name" + i, "Vlaue0" + i));
            fireTableRowsInserted(rows.size() - 1, rows.size() - 1);
        }

        @Override
        public String getColumnName(int column) {
            return column == 0 ? "Name" : "Value";
        }
    }

}

在将 rows 变量标记为 volatile 之前,我想知道如果我已经工作了,为什么我必须这样做。而且,上面链接的问题也提到了synchronized 关键字。我不明白如何使用synchronized 关键字解决线程看不到最新值的问题。对此的任何解释也表示赞赏。

【问题讨论】:

    标签: java multithreading swing synchronized volatile


    【解决方案1】:

    将调用 dm.addElement(count++); 封装在 SwingUtilities.invokeAndWait() 中

    来自 javadoc

     * Causes <code>doRun.run()</code> to be executed synchronously on the
     * AWT event dispatching thread.  This call blocks until
     * all pending AWT events have been processed and (then)
     * <code>doRun.run()</code> returns. This method should
     * be used when an application thread needs to update the GUI.
     * It shouldn't be called from the event dispatching thread.
     * Here's an example that creates a new application thread
     * that uses <code>invokeAndWait</code> to print a string from the event
     * dispatching thread and then, when that's finished, print
     * a string from the application thread.
     * <pre>
     * final Runnable doHelloWorld = new Runnable() {
     *     public void run() {
     *         System.out.println("Hello World on " + Thread.currentThread());
     *     }
     * };
     *
     * Thread appThread = new Thread() {
     *     public void run() {
     *         try {
     *             SwingUtilities.invokeAndWait(doHelloWorld);
     *         }
     *         catch (Exception e) {
     *             e.printStackTrace();
     *         }
     *         System.out.println("Finished on " + Thread.currentThread());
     *     }
     * };
     * appThread.start();
     * </pre>
    

    【讨论】:

      【解决方案2】:

      但即使没有使列表不稳定,更新似乎也有效。

      是的,它可能会在 99.9% 的时间内继续工作。

      Swing 被设计为在事件调度线程上完成所有更新。这是为了防止从不同的线程进行更新。

      在您的情况下,您实际上仍然只在一个线程上完成更新,因此您不太可能遇到问题。但是,如果您确实遇到问题,您将无法重现该问题,因为它是随机的,您不希望浪费时间调试随机但。

      因此,请确保在 EDT 上完成所有更新。阅读 Concurrency 上的 Swing 教程部分了解更多信息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多