0

下面的代码片段是一个名为“Foo”的线程,它会休眠 1 分钟,然后将1 分钟内输入的数据复制到日志文件中。

         while(isStarted) {
           try {
              Thread.sleep(60000); // sleep for 1 minute
              ArrayList<String> keyStrokeList = nativeMethods.getKeyStrokeList();
              int result = copy.copyToLogFile(keyStrokeList);
              System.out.println(result);
           } catch(Exception exc) {
               exc.printStackTrace();
             }
         }

我将描述一种情况:

Foo线程已经完成了对最后一分钟输入的所有数据的复制,并且从休眠到现在已经 30 秒。该线程不知道在睡眠时有几个键被敲击的情况,永远无法将击键复制到日志文件中System.exit(0)

有什么办法可以中断这个线程,即唤醒它并要求它将数据复制到日志文件

请讨论我应该如何解决这个问题。

问题中的情况:

loop started

thread is sleeping and will sleep for 1 minute

after a minute,it gets the keys tapped in the last 1 minute and copies all that
to a file

Thread sleeps again..and will sleep for 1 minute before it copies the keystrokes

It has been about 30 seconds and thread will sleep for 30 seconds more before it starts
copying the key strokes

suddenly the user presses exit button in the application

The user wants that key strokes be recorded till the second he presses exit

I cannot do System.exit(0) before checking the thread is asleep or not

How do I do this. Should I awake it or make a different call to the list and get the 
key strokes because they are being recorded ? And how shall I awake it ?
4

3 回答 3

1

你在那儿……

while(isStarted) {
    try {
        Thread.sleep(60000); // sleep for 1 minute
    } catch(InterruptedException exc) {
        exc.printStackTrace();
    }
    ArrayList<String> keyStrokeList = nativeMethods.getKeyStrokeList();
    int result = copy.copyToLogFile(keyStrokeList);
    System.out.println(result);
}

您需要提供一种终止循环的方法...

public void dispose() {
    isStarted = false;
    interrupt();
    try {
        join();
    } catch(InterruptedException exc) {
        exc.printStackTrace();
    }
}

您还应该知道 JVM 不会退出,直到所有非守护线程都完成(在正常关闭下)。这意味着您可以调用System.exit(0)并且 JVM 不会终止,直到记录器线程终止。

你可以使用它,但附加一个关闭钩子,它可以调用dispose记录器线程上的方法......只是一个想法

于 2012-10-07T10:32:16.570 回答
0

您应该使用 2 个线程之间的共享对象来实现等待/通知模式,而不是 Thread.sleep(..) 方法。

在您的情况下,有 2 个线程:

  • 它以 1 分钟的间隔读取缓冲区。(线程 1)
  • 哪个将首先收到“退出”事件。(线程 2)

因此,每当您创建 Thread1 的实例时,您都可以将 Java 对象 (new Object()) 传递给它。阅读器线程可以使用 object.wait(60*1000); 因此,如果在 1 分钟内未调用 object.notify(),它将最多休眠 1 分钟。如果在此期间调用 object.notify(),线程将立即恢复。

因此,每当用户想要退出应用程序时,您都可以调用 object.notify(); 这将恢复阅读器线程。

如果由于我的英语不好而未能向您解释解决方案,请告诉我。我会给你一个代码示例。

于 2012-10-07T10:31:31.483 回答
0

这是一个相当简单的测试用例来展示一种方法:

public class InterruptTest
{
    @Test
    public void test() throws InterruptedException
    {
        //Create the logging thread and start it
        LogRunnable runnable = new LogRunnable();
        Thread t = new Thread(runnable);
        t.start();

        //Wait some time
        Thread.sleep(3500);

        System.out.println("User has pressed exit, starting shutdown");

        //Tell the runnable to shut down
        runnable.halt();
        //Interrupt the thread to wake it up
        t.interrupt();
        //Wait until thread terminates
        t.join();

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

    private static class LogRunnable implements Runnable
    {
        private static final int SLEEPMS = 2000;

        private boolean isStarted = true;
        private int runCount = 1;

        public void halt()
        {
            this.isStarted = false;
        }

        public void run()
        {
            while(isStarted)
            {
                try
                {
                    Thread.sleep(SLEEPMS);
                }
                catch(InterruptedException e)
                {
                    System.out.println("Interrupted");
                }
                catch(Exception exc)
                {
                    exc.printStackTrace();
                }

                //Do work
                System.out.println("Work done " + runCount++);
            }
        }
    }
}

输出:

Work done 1
User has pressed exit, starting shutdown
Interrupted
Work done 2
Exiting
  • 当用户按下退出键时,您向主线程发出信号以开始关闭一切(在测试用例中,它只是等待一段时间)
  • 记录线程被告知通过中断()调用停止和唤醒
  • 在退出之前,主线程调用join()以等待日志线程完成,您可以考虑使用一个需要超时的重载,以防出现问题
  • 日志线程以 唤醒InterruptedException,捕获后完成代码并终止
  • 日志记录线程终止后,主线程从join()-call 返回并终止
于 2012-10-07T10:42:35.527 回答