Java 尝试异步(线程)显示时出现SWTException

Java 尝试异步(线程)显示时出现SWTException,java,multithreading,exception,swt,Java,Multithreading,Exception,Swt,问题:我需要3个线程。Thread1读取一个int值并在该值更改时启动一个操作(涉及UI)。Thread2是UI。Thread3是Thread1注意到int已更改时应执行的操作。现在,当我启动thread2,然后执行 display.async(new Thread1()) 它不会显示UI,因为稍后会调用open()-方法。当我先打开()然后显示.async()时,它会立即抛出一个SWTException: Exception in thread "Thread-0" org.e

问题:我需要3个线程。Thread1读取一个int值并在该值更改时启动一个操作(涉及UI)。Thread2是UI。Thread3是Thread1注意到int已更改时应执行的操作。现在,当我启动thread2,然后执行

    display.async(new Thread1())
它不会显示UI,因为稍后会调用open()-方法。当我先打开()然后显示.async()时,它会立即抛出一个SWTException:

    Exception in thread "Thread-0" org.eclipse.swt.SWTException: Failed to execute runnable (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.widgets.Synchronizer.runAsyncMessages(Unknown Source)
        at org.eclipse.swt.widgets.Display.runAsyncMessages(Unknown Source)
        at org.eclipse.swt.widgets.Display.readAndDispatch(Unknown Source)
        at sokobangui.SokobanGUIManager.run(SokobanGUIManager.java:57)
        at java.lang.Thread.run(Unknown Source)
    Caused by: 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.Display.checkDisplay(Unknown Source)
        at org.eclipse.swt.widgets.Display.create(Unknown Source)
        at org.eclipse.swt.graphics.Device.(Unknown Source)
        at org.eclipse.swt.widgets.Display.(Unknown Source)
        at org.eclipse.swt.widgets.Display.(Unknown Source)
        at sokobangui.SokobanGUIManager.run(SokobanGUIManager.java:35)
        at java.lang.Thread.run(Unknown Source)
        at org.eclipse.swt.widgets.RunnableLock.run(Unknown Source)
        ... 5 more
当我分别启动thread1和thread2而不尝试同步它们时,它工作正常,直到我尝试使用thread2初始化thread3。然后我得到这个:

    Exception in thread "Thread-1" 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.Control.getShell(Unknown Source)
        at sokobangui.GUICoordinator.switchToRoboControl(GUICoordinator.java:120)
        at sokobangui.GUIListener.run(GUIListener.java:15)
        at java.lang.Thread.run(Unknown Source)
因此,如果有人问我这里发生了什么,我会说同步线程有一些问题,因为据我所知,显示线程需要“知道”哪些线程将修改曲面。但是我不知道如何解决这个问题

下面是一些代码片段:(thread1=GUIListener;thread2=SokobanGUIManager;thread3=SwitchToRoboControl)


根本不要启动Gulistener。使用“机器人解谜”的菜单侦听器,它将安排游戏解谜,然后执行一些UI操作。这可以通过两种方式实现:

1) 在“机器人解谜”听者中直接解决游戏

2) 启动一个线程,该线程计算解决方案,然后使用“Display.asyncexec”(或syncExec)在UI中显示解决方案

请参见如何将侦听器附加到菜单项


希望这会有所帮助。

所以,Thread3是Thread1发现状态更改时执行操作的一个,对吗?也许一些代码片段可以更好地解释您的用例。你介意分享吗?我添加了一些片段,希望这有助于理解这个问题。但是你是对的,当且仅当thread1(=Guilister)注意到状态更改时,thread3(=SwitchToRoboControl)应该执行一些在UI上应该可见的操作(基本上移动图标)。Guilister是否执行任何UI操作?我是说动作是同步执行的,不是。它只调用进入GUI Coordinator.switchToRoboControl()的connector.switchToRoboControl(),并启动执行UI操作(或应该执行的)的第三个线程。GUIListener实际上只是读取值并调用该方法。是什么将GUIStatus.status的值更改为GUIStatus.INGAME_ROBOT?好的,到目前为止,这解决了问题,但出现了一个新问题:解决谜题的线程应该在机器人执行每一步后更新UI-方法工作正常,但由于某些原因,UI只有在线程终止并死亡后才会更新,因此UI上的图标“跳”到其目标。。。有什么办法解决这个问题吗?因为这个问题最初是我开始使用线程的原因,但显然没有帮助:-/如果使用解决方案1,那么结果就是UI被阻塞。使用第二种解决方案-启动一个常规线程(通过thread.start())并使用Display.asyncexec/syncExcec从中更新UI。等等,我想我需要正确理解这一点:我执行threadSwitchToRoboControl.start()。在run()中,我需要调用Display.async(SokobanGUIManager)?因此,将GUI与解决方案同步,而不是相反?不,当我这样做时,我会得到更多的SWTExceptions…:无法执行runnable;+线程访问无效:“在org.eclipse.swt.widgets.Display.runAsyncMessages(未知源)在org.eclipse.swt.widgets.Display.readAndDispatch(未知源)”侦听器中创建一个SolverThread,您只需调用thread.start()即可启动它。然后,如果每次需要更新UI,只需在该线程中将更新打包为可运行文件,并使用Display.asyncExec执行即可。每次尝试直接从SolverThread访问UI时,您都会得到“无效线程访问”。


    public class StartSokobanSolver {
        public static void main(String[] args) {
            GUIStatus.status = GUIStatus.MAIN;

            Thread manager = new Thread(new SokobanGUIManager());
            manager.start();

            //Thread listener = new Thread(new GUIListener());
            //listener.start();
        }
    }

    public class SokobanGUIManager implements Runnable {
        public void run() {
            this.display = new Display();
            this.display.asyncExec(new Thread(new GUIListener()));

            this.shell = new Shell(this.display);

            goToMainMenu();

            this.shell.open();

            while (!this.shell.isDisposed()) {
                if (!display.readAndDispatch()) {
                display.sleep();
                }
            }
            GUIStatus.status = GUIStatus.END;
        }
    }

    public class GUIListener implements Runnable {
        private static GUICoordinator connector;

        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()) {
                //try{
                    while(GUIStatus.status != GUIStatus.END) {
                        System.out.println("GUI-Status: " + GUIStatus.status);
                        if(GUIStatus.status == GUIStatus.INGAME_ROBOT) {
                            System.out.println("InGameRobot Start");
                            connector.switchToRoboControl();
                            System.out.println("InGameRobot End");
                            GUIStatus.status = GUIStatus.INGAME_SOLVED;
                            connector.isSolved();
                        } else {
                            System.out.println("Else");
                            try{ Thread.sleep(5000); } catch(Exception e) {}
                        }
                        if(GUIStatus.status == GUIStatus.END) {
                            Thread.currentThread().interrupt();
                        }
                    }
                    /*} catch(Exception e) {
                    System.out.println("Ende des Threads : " + e.toString());
                    Thread.currentThread().interrupt();
                    Not in the code atm to get the full exception message!
                }*/
            }
        }

        protected static void setCoordinator(GUICoordinator c) {
            connector = c;
        }
    }

    public class GUICoordinator {
        ...
        protected void switchToRoboControl() {
            if(this.roboControl != null) {
                Solution solution = new Solution("1u:1l:1d"); 
                Thread roco = new Thread(new SwitchToRoboControl(this.map, this,  this.mapArea.getShell(), solution));
                Display.getDefault().asyncExec(roco);
                roco.start();
                System.out.println("Thread started");
            } else {
                System.out.println("Epic fail");
            }
        }
    }

    public class SwitchToRoboControl implements Runnable {
        ...

        public SwitchToRoboControl(Map map, GUICoordinator gui, Shell shell, Solution solution) {
            this.map = map;
            this.gui = gui;
            this.shell = shell;
            this.solution = solution;
        }

        @Override
        public void run() {
            ...action to be performed
        }
    }