【问题标题】:Timer in Java ThreadJava线程中的定时器
【发布时间】:2021-12-03 23:43:14
【问题描述】:

我有一个线程负责执行一些进程。我想让这些处理每 3 秒完成一次。我已经使用了下面的代码,但是当线程启动时,什么也没有发生。 我假设当我为我的计时器定义一个任务时,它会在时间间隔内自动执行ScheduledTask,但它根本不做任何事情。 我错过了什么?

class temperatureUp extends Thread 
{
    @Override
    public void run()
    {
    TimerTask increaseTemperature = new TimerTask(){

        public void run() {
        try {
            //do the processing 
        } catch (InterruptedException ex) {}
        }
    };

    Timer increaserTimer = new Timer("MyTimer");
    increaserTimer.schedule(increaseTemperature, 3000);

    }
};

【问题讨论】:

  • 您确定要创建temperatureUp 线程并在其上调用start() 吗?这段代码对我来说很好。
  • 为什么要同时使用线程和计时器?计时器在它自己的线程上运行
  • 我认为你应该重新考虑你的程序的结构。您必须考虑一个全局计时器(不是针对每个线程)。如果这些过程花费的时间超过 3 秒怎么办?你将如何优雅地结束它们?您需要提供更多信息和更多代码:)
  • @AljoshaBre 我仍然不知道这段代码有什么问题。

标签: java multithreading timer


【解决方案1】:

您的代码 sn-p 中的一些错误:

  • 您扩展了 Thread 类,这不是一个很好的做法
  • Thread 中有 Timer?这没有意义,因为 Timer 独立运行 Thread

您应该(在必要时/在必要时)实现Runnable 参见here 以获取简短示例,但是我看不到您提供的sn-p 中需要ThreadTimer .

请参阅下面的 Timer 工作示例,每次调用它时(每 3 秒)只会将计数器加一:

import java.util.Timer;
import java.util.TimerTask;

public class Test {

    static int counter = 0;

    public static void main(String[] args) {

        TimerTask timerTask = new TimerTask() {

            @Override
            public void run() {
                System.out.println("TimerTask executing counter is: " + counter);
                counter++;//increments the counter
            }
        };

        Timer timer = new Timer("MyTimer");//create a new Timer

        timer.scheduleAtFixedRate(timerTask, 30, 3000);//this line starts the timer at the same time its executed
    }
}

附录:

我做了一个简短的例子,将Thread 合并到混合中。所以现在TimerTask 只会每 3 秒将counter 增加 1,而Thread 将在每次检查计数器时显示counters 值休眠 1 秒(它将在@987654337 之后终止自身和计时器@):

import java.util.Timer;
import java.util.TimerTask;

public class Test {

    static int counter = 0;
    static Timer timer;

    public static void main(String[] args) {

        //create timer task to increment counter
        TimerTask timerTask = new TimerTask() {

            @Override
            public void run() {
                // System.out.println("TimerTask executing counter is: " + counter);
                counter++;
            }
        };

        //create thread to print counter value
        Thread t = new Thread(new Runnable() {

            @Override
            public void run() {
                while (true) {
                    try {
                        System.out.println("Thread reading counter is: " + counter);
                        if (counter == 3) {
                            System.out.println("Counter has reached 3 now will terminate");
                            timer.cancel();//end the timer
                            break;//end this loop
                        }
                        Thread.sleep(1000);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        });

        timer = new Timer("MyTimer");//create a new timer
        timer.scheduleAtFixedRate(timerTask, 30, 3000);//start timer in 30ms to increment  counter

        t.start();//start thread to display counter
    }
}

【讨论】:

    【解决方案2】:
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class ThreadTimer extends TimerTask{
        static int counter = 0;
    
        public static void main(String [] args) {
            Timer timer = new Timer("MyTimer");
            timer.scheduleAtFixedRate(new ThreadTimer(), 30, 3000);
        }
    
        @Override
        public void run() {
            // TODO Auto-generated method stub
            System.out.println("TimerTask executing counter is: " + counter);
            counter++;
       }
    
    }
    

    【讨论】:

      【解决方案3】:

      为了每三秒执行一次操作,您应该使用 scheduleAtFixedRate(请参阅javadoc)。

      但是,您的代码实际上并没有做任何事情,因为您创建了一个线程,在该线程的运行停止之前,您在其中启动了一个计时器(没有更多可做的事情)。当定时器(单拍)触发时,没有线程可以中断(之前运行完毕)。

      class temperatureUp extends Thread 
      {
          @Override
          public void run()
          {
          TimerTask increaseTemperature = new TimerTask(){
      
              public void run() {
              try {
                  //do the processing 
              } catch (InterruptedException ex) {}
              }
          };
      
          Timer increaserTimer = new Timer("MyTimer");
          //start a 3 seconds timer 10ms later
          increaserTimer.scheduleAtFixedRate(increaseTemperature, 3000, 10);
      
          while(true) {
               //give it some time to see timer triggering
               doSomethingMeaningful();
          }
      }
      

      【讨论】:

        【解决方案4】:

        我认为您使用的方法具有签名 schedule(TimerTask task, long delay) 。所以实际上你只是延迟了唯一执行的开始时间。

        要安排它每 3 秒运行一次,您需要使用此方法 schedule(TimerTask task, long delay, long period),其中 third 参数用于给出周期间隔。

        您可以参考此处的 Timer 类定义以获得进一步帮助

        http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Timer.html

        【讨论】:

        • 使用increaserTimer.schedule(increaseTemperature, 2000, 2000); 行仍然没有任何反应!
        • @Elham - 我之前没有注意到,但你是从另一个线程中产生一个新线程?这是一个非常错误的做法。考虑更改您的结构,以便从全局级别生成和调度线程。这是一个示例项目的链接,可以帮助您更改结构:roseindia.net/java/example/java/util/CertainAndRepeatTime.shtml
        • 换句话说,我不能使用 Timer 来安排由线程完成的一系列动作。对吗?
        • @Elham : TimerTask 本身可以称为线程。您只需在 run() 函数中定义线程功能即可。只是没有必要扩展 Thread 类并使您的代码复杂化。你必须有一个父类,仪式?从该父类生成一个 TimerTask ,并具有预定的延迟和间隔。一定要添加一些退出条件,否则这个任务会一直运行到 WebApp 启动为止。
        • 这是一个课堂作业。我需要为这个程序使用线程类。
        【解决方案5】:

        Timer & TimerTask 是旧版

        TimerTimerTask 类现在是 legacy。要在特定时间运行代码,或重复运行代码,请使用 scheduled executor service

        引用Timer类Javadoc:

        Java 5.0 引入了 java.util.concurrent 包,其中的并发实用程序之一是 ScheduledThreadPoolExecutor,它是一个线程池,用于以给定的速率或延迟重复执行任务。它实际上是 Timer/TimerTask 组合的更通用替代品,因为它允许多个服务线程,接受各种时间单位,并且不需要子类化 TimerTask(只需实现 Runnable)。用一个线程配置 ScheduledThreadPoolExecutor 使其等效于 Timer。

        执行器框架

        在现代 Java 中,我们使用 Executors framework 而不是直接寻址 Thread 类。

        将您的任务定义为RunnableCallable。您可以使用如下所示的紧凑 lambda 语法。或者您可以使用常规语法来定义实现Runnable(或Callable)接口的类。

        每隔一段时间让ScheduledExecutorService 对象执行您的Runnable 对象的代码。

        ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor() ;
        
        Runnable task = () -> { 
            System.out.println( "Doing my thing at: " + Instant.now() );
        };
        
        long initialDelay = 0L ; 
        long period = 3L ;
        TimeUnit timeUnit = TimeUnit.SECONDS ;
        scheduledExecutorService.submit( task , initialDelay, period , timeUnit ) ;
        
        …
        scheduledExecutorService.shutdown() ;  // Stops any more tasks from being scheduled.
        scheduledExecutorService.awaitTermination() ;  // Waits until all currently running tasks are done/failed/canceled. 
        

        请注意,我们没有直接管理上述代码中的任何Thread 对象。管理线程是执行器服务的工作。

        提示:

        • 当不再需要时,或者当您的应用程序退出时,请始终正常关闭您的执行程序服务。否则后备线程池可能会像僵尸一样无限期地继续下去?‍♂️。
        • 考虑将任务的工作代码封装在 try-catch 中。到达计划的执行器服务的任何未捕获的异常或错误都会导致以静默方式停止进一步计划运行。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-02-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-01-18
          • 2013-03-23
          相关资源
          最近更新 更多