Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 代码名1:需要访问UI的后台线程_Multithreading_User Interface_Codenameone_Edt - Fatal编程技术网

Multithreading 代码名1:需要访问UI的后台线程

Multithreading 代码名1:需要访问UI的后台线程,multithreading,user-interface,codenameone,edt,Multithreading,User Interface,Codenameone,Edt,我的应用程序有需要访问UI的后台线程。 想象一下,一个国际象棋程序(AI)在棋盘上下棋之前会“思考”几秒钟。 线程运行时,UI被阻止输入,但仍有输出 涉及3个线程: 美国东部夏令时 使用invokeAndBlock的think线程,输出有关搜索过程的信息(在文本字段中),例如当前移动、搜索深度和搜索值 一个时钟线程,以thread.start()开头,每秒更新一次白色或黑色(TextFields)使用的时间 在搜索过程中(invokeAndBlock),可以使用stop按钮强制停止搜索(未显示)

我的应用程序有需要访问UI的后台线程。 想象一下,一个国际象棋程序(AI)在棋盘上下棋之前会“思考”几秒钟。 线程运行时,UI被阻止输入,但仍有输出

涉及3个线程:

  • 美国东部夏令时
  • 使用invokeAndBlock的think线程,输出有关搜索过程的信息(在文本字段中),例如当前移动、搜索深度和搜索值
  • 一个时钟线程,以thread.start()开头,每秒更新一次白色或黑色(TextFields)使用的时间
  • 在搜索过程中(invokeAndBlock),可以使用stop按钮强制停止搜索(未显示)

    下面是我当前的实现。我的问题是:这是实现这一目标的正确方式吗

    (我读了第二部分。)

    编辑:think、showWhiteTime和showBlackTime的新版本

    // version 2, replaced invokeAndBlock by Thread.start() and callSerially
    void think() {
        blockUI();                      // disable buttons except stopButton
        new Thread(() -> {              // off the EDT
            clock.start(board.player);  // this thread calls showWhiteTime or showBlackTime every second
            move = search(board, time); // e.g. for 10 seconds
            clock.stop();
            callSerially(() -> {
                animateMove(board, move);
                clock.start(board.player);
                freeUI();
            });
        }).start();
    }
    
    // version 2, added callSerially
    void showWhiteTime(String s) {      // access UI off the EDT
        callSerially(() -> {
            whiteTime.setText(s);
        });
    }
    
    // version 2, added callSerially
    void showBlackTime(String s) {      // access UI off the EDT
        callSerially(() -> {
            blackTime.setText(s);
        });
    }
    

    虽然我可以避免您在
    showWhiteTime
    showBlackTime
    中遇到的EDT冲突,但大多数代码都很好。EDT违规可能会以奇怪的方式突然失败,因为您触发异步操作,事情可能会很快变得糟糕。我建议在模拟器中打开EDT违规检测工具

    使用
    invokeAndBlock
    时要记住两件事:

    • 它比普通线程慢
    • 在某些情况下,它会阻止挂起事件,因此将其作为挂起事件链的一部分是有问题的
    第二点很难理解,也是许多错误的根源,因此值得解释一下

    考虑以下代码:

     buttonA.addActionListener(e -> {
           doStuff();
           invokeAndBlock(...);
           doOtherStuff();
     });
     buttonA.addActionListener(e -> doSomethingImportant());
    
    这可能看起来不现实,因为您通常不会一个接一个地添加两个单独的侦听器,但这种情况已经足够了,例如,如果一个更改触发另一个更改,等等

    invokeAndBlock
    期间,
    buttonA
    的当前事件处理将被阻止。这意味着
    doOtherStuff()
    将等待
    invokeAndBlock
    并且
    doSomethingImportant()
    将等待

    如果
    doSomethingImportant()
    显示另一个表单,您可能会出现奇怪的行为,例如在您按下按钮并做了许多其他事情之后,您的表单会突然发生变化


    因此,您需要非常清楚如何使用
    invokeAndBlock

    Re“需要访问UI的后台线程”。不要这样做。UI线程和其他线程之间的耦合应该非常松散。UI线程应该显示程序的状态。当其他线程以用户可能希望看到的方式更改该状态时,它们应该能够通知UI。UI应该能够通知后台线程,用户已经以可能很重要的方式更改了状态。但大多数情况下,它们应该彼此独立运行。例如,“blockUI()…search()…freeUI()”。也不要去那里。用户界面应该始终对用户操作做出响应,即使响应只是说:“你现在不能这样做,因为轮到你移动了。”没有响应的用户界面会产生一种错觉,认为你的程序不可靠,即使它不可靠。一个简洁的用户界面会让人产生一种错觉,认为你的程序比实际速度快。“不要去那里”不是一个有用的答案。你曾经使用过国际象棋程序吗?这不是一个答案。旨在作为替代设计建议。是的,我不是一个认真的球员,但我曾经和一台机器对抗过。我不会向我的任何朋友推荐一个象棋程序,如果它的用户界面在“思考”时被锁定。好的,谢谢,我会考虑的。但问题其实是关于代码名一线程和访问用户界面。谢谢你的回答。是的,我已经在模拟器中使用了完整的EDT违规检测。如果我在showSearchInfo中不连续使用callSerially,它会报告违规行为。但是,它不会报告showWhiteTime和showBlackTime中的违规行为。我是否正确理解您建议在这些方法中也使用callSerially?(请参阅有问题的编辑。)您是否也建议在这种情况下避免invokeAndBlock?think()的第2版怎么样?(参见有问题的编辑。)违规检测并不完美。它可能会错过一些问题,并对一些不存在的问题保持警惕。是的,如果您从单独的线程访问UI,即使违例检测工具没有检测到,也应该使用callSerially。异步方法会更快,但可读性较差。这是你的选择,两者都会起作用。
     buttonA.addActionListener(e -> {
           doStuff();
           invokeAndBlock(...);
           doOtherStuff();
     });
     buttonA.addActionListener(e -> doSomethingImportant());