Java:尝试从其他线程更新SWT Label时出现NullPointerException

时间:2015-03-02 16:59:14

标签: java multithreading swt

据我所知,通过在线阅读以及其他在线资源(例如this),您无法从其他线程访问SWT对象。
的确,当我尝试这样做时:

课程菜单:

public class Menu {

    public static void main(String args[]) {

        System.out.println("Main thread: "+Thread.currentThread().getId()); // prints 1

        final Display display=new Display();
        final Shell shell=new Shell(display);
        Label l=new Label(shell, SWT.SHADOW_IN);
        l.setText("Some label");
        l.pack();

        SecondThread second_thread=new SecondThread(l);
        Thread t=new Thread(second_thread);
        t.start();

        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        display.dispose();
    }
}

Class SecondThread:

public class SecondThread implements Runnable {

    private Label label;
    public SecondThread(Label l) {
        label=l;
    }

    @Override
    public void run() {
        System.out.println("Second thread: "+Thread.currentThread().getId()); // prints 8

        for (int i=0; i<10000; ++i) {

            try {
                Thread.sleep(3000); // waiting three seconds...
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            label.setText("i is: "+i); // SWTException is thrown here
        }
    }
}

抛出SWTException:

Exception in thread "Thread-0" org.eclipse.swt.SWTException: Invalid thread access
    at org.eclipse.swt.SWT.error(Unknown Source)
    at org.eclipse.swt.SWT.error(Unknown Source)
    at org.eclipse.swt.SWT.error(Unknown Source)
    at org.eclipse.swt.widgets.Widget.error(Unknown Source)
    at org.eclipse.swt.widgets.Widget.checkWidget(Unknown Source)
    at org.eclipse.swt.widgets.Label.setText(Unknown Source)
    at tst.SecondThread.run(SecondThread.java:25)
    at java.lang.Thread.run(Thread.java:745)

此处建议的解决方案,以及其他在线资源,是使用Display的asyncExec()方法,其中包含:

  

导致runnable的run()方法被调用   用户界面线程在下一个合理的机会。呼叫者,召集者   此方法继续并行运行,并且不会通知   runnable已经完成。将null指定为runnable简单   运行时唤醒用户界面线程。

所以我试着替换:

SecondThread second_thread=new SecondThread(l);
Thread t=new Thread(second_thread);
t.start();

使用:

SecondThread second_thread=new SecondThread(l);
display.asyncExec(second_thread);

但事实证明,这并没有真正创建新的执行线程,因为输出表明:

Main thread: 1
Second thread: 1

因此,Thread.sleep(3000)调用使GUI窗口无响应......

所以我尝试了另一种方法:

菜单:

public class Menu {

    public static void main(String args[]) {

        System.out.println("Main thread: "+Thread.currentThread().getId()); // prints 1

        final Display display=new Display();
        final Shell shell=new Shell(display);
        Label l=new Label(shell, SWT.SHADOW_IN);
        l.setText("Some label");
        l.pack();

        SecondThread second_thread=new SecondThread(l);
        Thread t=new Thread(second_thread);
        t.start();

        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        display.dispose();
    }
}

SecondThread:

public class SecondThread implements Runnable {

    private Label label;
    public SecondThread(Label l) {
        label=l;
    }

    @Override
    public void run() {
        System.out.println("Second thread: "+Thread.currentThread().getId()); // prints 8

        for (int i=0; i<10000; ++i) {

            try {
                Thread.sleep(3000); // waiting three seconds...
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            updateLabel("i is: "+i);
        }
    }

    private void updateLabel(final String string) {

        Display display=Display.getCurrent(); // display is not null...

        display.asyncExec(new Runnable() { // throws NullPointerException... 

            @Override
            public void run() {
                System.out.println("test");
                label.setText(string);
            }

        });
    }
}

不幸的是,这会抛出NullPointerException:

Main thread: 1
Second thread: 8
Exception in thread "Thread-0" java.lang.NullPointerException
    at tst.SecondThread.updateLabel(SecondThread.java:33)
    at tst.SecondThread.run(SecondThread.java:25)
    at java.lang.Thread.run(Thread.java:745)

我不知道为什么......
有谁知道可能导致这种情况的原因?

1 个答案:

答案 0 :(得分:3)

您的SecondThread不是用户界面线程,因此Display.getCurrent()将返回null,因为只有用户界面线程具有当前显示。

使用Display.getDefault()从任何线程获取显示。