Java:NullPointerException尝试从其他线程更新SWT标签时

Java:NullPointerException尝试从其他线程更新SWT标签时,java,multithreading,swt,Java,Multithreading,Swt,通过阅读SO和其他在线来源(例如),我了解到您无法从其他线程访问SWT对象。 事实上,当我尝试这样做时: 类菜单: public class Menu { public static void main(String args[]) { System.out.println("Main thread: "+Thread.currentThread().getId()); // prints 1 final Display display=new Di

通过阅读SO和其他在线来源(例如),我了解到您无法从其他线程访问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();
    }
}
第二类线程:

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
        }
    }
}
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);
            }

        });
    }
}
这里以及其他在线资源中建议的解决方案是使用Display的
asyncExec()
方法,该方法:

使runnable的run()方法由 用户界面线程在下一个合理的机会。来电者 此方法的一部分将继续并行运行,并且在 runnable已完成。简单地将null指定为可运行 运行时唤醒用户界面线程

所以我试着替换:

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 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
        }
    }
}
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);
            }

        });
    }
}
我不知道为什么…

有人知道这可能是什么原因吗?

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


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

太好了!它工作!!!我可以发誓我检查了
display
是否为空。。。无论如何,非常感谢。
updateLabel
中的runnable还有另一个问题:在访问
label.isDisposed()
之前,您应该检查
标签是否仍然存在,因为它可能已被处理。
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)