【问题标题】:java.awt.Robot thread can't be stopped/destroyed?java.awt.Robot 线程无法停止/销毁?
【发布时间】:2012-11-11 06:15:31
【问题描述】:

我使用 java.awt.Robot 制作了桌面远程控制应用程序,并且工作正常。 应用程序集成在另一个应用程序系统中,所以我希望能够从外部系统启动/停止远程控制,但我发现了一个奇怪的问题 - 我无法停止机器人。

我尝试了几件事:在线程内运行它(所以我可以停止线程),使机器人对象为空,而不是调用 System.gc() 但问题不在于引用它仍在运行的机器人线程(毕竟其他被摧毁)。 在调试中我可以看到正在运行的线程:Daemon Thread [AWT-Windows] (Running)。

这里是重现我的问题的代码:

public class RobotDestroy {

  public static void main(String[] args) {

    try {
        Robot r = new Robot();
    } catch (AWTException e) {
        e.printStackTrace();
    }

    }

}

有没有人经历过类似的事情? 有什么解决办法吗?

谢谢

编辑:

这是在可以停止的线程中运行 Robot 但 Robot 实例仍在运行的示例:

public class RobotDestroy {

public static void main(String[] args) {

    RobotThread rt = new RobotThread();
    rt.start(); 

    try {
        //do some work before thread shut down
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    rt.shutdown();          
}

private static class RobotThread extends Thread {

    public Robot robot;
    volatile boolean alive;

    public RobotThread(){
        try {
            this.robot = new Robot();
            this.alive = true;
        } catch (AWTException e) {
            e.printStackTrace();
        }
    }

    public void run(){

        while(alive){
            System.out.println("alive");
            try{
                robot.delay(5000);
                sleep(1000);

            }catch(Exception e){
                e.printStackTrace();
            }
        }           
    }

    public void shutdown(){
        this.alive = false;
        robot = null;
        System.out.println("shutdown");
    }       
}

}

编辑 2

我尝试了医生杀手的建议,虽然这是一个很好的建议,但机器人线程仍在运行。最好的证明方法是在创建机器人实例之前和之后打印出线程:

    Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
    Thread[] threadArray = threadSet.toArray(new Thread[threadSet.size()]);

    for (int i = 0; i < threadArray.length; i++) {
        System.out.println(threadArray[i].getName());
    }

更新: 经过大量调试后,我意识到问题不在于 java.awt.Robot 类 - 是 java.awt.Toolkit 启动了 AWT-Window 线程,该线程在应用程序结束后仍然运行。 Robot 对象具有 RobotPeer (java.awt.peer.RobotPeer),它由以下方法返回: ((ComponentFactory)toolkit).createRobot(this, screen);

【问题讨论】:

  • 是的:herehere 发生了完全相同的事情
  • 不可阻挡的机器人?这不好。
  • 我手头没有直接证据,但我建议 tat Robot 实际上正在启动另一个非守护线程(如果我没记错的话,它正在启动 AWT EventQueue)。虽然您可以阻止机器人实例,但我知道的唯一方法是停止 EventQueue 一个 va System.exit
  • 您是否尝试过使用调试器在剩余线程中停止执行以查看它实际在做什么?这可能会提示它为什么没有关闭。
  • 在您上次更新后,您似乎确定了问题的根源……但是您是如何解决的? IE。您最终是如何停止 AWT-Window 线程的?

标签: java thread-safety awtrobot


【解决方案1】:

通常你会在接收远程事件的线程的 while(true) 循环中放置一个标志,这样你就会有类似 while(isAlive) ... 读取远程事件 ... 如果远程事件断开连接你退出循环,机器人将不再获得命令。

机器人还活着,只是因为你的程序一直在调用它……你要停止循环

也将它包含在您的 RobotThread 中

import java.awt.AWTException;
import java.awt.Robot;
import java.util.LinkedList;

public class RobotDestroy {

    public static void main(String[] args) {
        //Set<Thread> threadSet = Thread.getAllStackTraces().keySet(); Thread[] threadArray = threadSet.toArray(new Thread[threadSet.size()]); for (int i = 0; i < threadArray.length; i++) { System.out.println("Init " + threadArray[i].getName()); }
        RobotThread rt = new RobotThread();
        rt.start(); 

        // Listen to the upcomming commands...and push them to the RobotThread

        rt.shutdown();          
    }

    private static class RobotThread extends Thread {

        public Robot robot;

        public RobotThread(){
            try {
                this.robot = new Robot();
            } catch (AWTException e) {
                e.printStackTrace();
            }
        }

        public void run(){
            Command currentCommand = getNextCommand();
            while(currentCommand.getType() != CommandType.KILL){
                // Process the command no sleep...
                // ...
                // ...

                currentCommand = getNextCommand();
            }

            System.out.println("DIED ");
        }

        private LinkedList<Command> commands = new LinkedList<Command>();

        enum CommandType {
            KILL,
            DO_SOMETHING
        }

        private synchronized Command getNextCommand() {
            while(commands.isEmpty()) {
                try {
                    System.out.println("WAITING");
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return commands.removeFirst();
        }

        public synchronized void pushCommand(Command comm) {
            commands.addLast(comm);
            notify();
        }

        public synchronized void shutdown(){
            commands.clear();
            pushCommand(new Command(CommandType.KILL));
            System.out.println("shutdown");
            //Set<Thread> threadSet = Thread.getAllStackTraces().keySet(); Thread[] threadArray = threadSet.toArray(new Thread[threadSet.size()]); for (int i = 0; i < threadArray.length; i++) { System.out.println("End " + threadArray[i].getName()); }
        }  

        class Command {
            private CommandType cmdType;
            public Command(CommandType type) {
                this.cmdType = type;
            }
            public CommandType getType() { return cmdType; }
        }
    }
}

【讨论】:

  • 不幸的是,这是不正确的。我有一个线程正在监听远程事件,当我停止它时,机器人还活着:) 我可以发布示例源,但相信我就是这样。
  • 机器人还活着,因为它启动了一个你无法控制的非守护线程,而不是凝聚力会阻止它;)
  • Robot 还活着是什么意思:Robot 是一个对象而不是线程:请发布更多代码(单独监听线程)
  • 我认为线程和机器人之间存在一些混淆......你的机器人在线程中......对吗?然后你有责任在需要时添加一些代码以退出机器人线程...... Thread 的 stop() 方法已被贬低并清楚地说明结束循环是你的责任
  • 正如我已经说过的,Robot 正在启动一个新的非守护线程,也就是事件调度线程,当你开始与 UI 交互时,这个线程会自动生成,你没有控制这个线程,所以即使你执行的线程结束,它也会让 EDT 继续运行。我知道除了 System.exit 之外没有办法停止这个线程
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-02
  • 2010-10-15
  • 1970-01-01
  • 1970-01-01
  • 2017-04-02
相关资源
最近更新 更多