Расписание таймера против scheduleAtFixedRate?

public class MyTimerTask extends TimerTask{

    @Override
    public void run() {
        int i = 0; 
        try {
            Thread.sleep(100000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Run Me ~" + ++i);
        System.out.println("Test");

    }

}

Case 1 :-
    TimerTask task = new MyTimerTask();
    Timer timer = new Timer();
    timer.schedule(task, 1000,6000); // line 1
    System.out.println("End"); // here is bebug point. 

Мое ожидание метода schedule() (согласно моему пониманию, приведенному в javadocs, где каждое выполнение запланировано после завершения выполнения предыдущей задачи), что два потока должны быть созданы после строки 1.

Один для timer, который порождает другой поток для задач. После того, как первый поток задачи умрет, будет создан другой и запущен. Но в точке отладки я вижу только один поток, соответствующий Timer. Почему бы не использовать поток для задач, которые реализуют Runnable?

Case 2 :-

    TimerTask task = new MyTimerTask();
    Timer timer = new Timer();
    timer.scheduleAtFixedRate(task, 1000,6000); // line 1
    System.out.println("End"); // here is bebug point. 

Мое ожидание метода scheduleAtFixedRate() (согласно моему пониманию, приведенному в javadocs, где каждое выполнение запланировано относительно запланированного времени выполнения начального выполнения), что около 17 потоков (не обращайте особого внимания на 17. Это может быть более или менее к этому. Но он должен быть больше 2 ) должен быть создан после строки 1.

Один для timer, который должен породить 16 других потоков, соответствующих двум каждой задаче. Если первая задача приостанавливается на 100 секунд, Timer должен создать другой поток, соответствующий следующей задаче, и аналогично для другой задачи. Но в точке отладки я вижу только один поток, соответствующий Timer. Здесь также я вижу последовательное выполнение задачи. Почему не 17 потоков?

ОБНОВЛЕНИЕ: – согласно ScheduleAtFixedRate javadocs, each execution is scheduled relative to the scheduled execution time of the initial execution. If an execution is delayed for any reason (such as garbage collection or other background activity), two or more executions will occur in rapid succession to "catch up. what does that mean? Мне кажется, что если вторая задача должна быть выполнена, даже если первая задача не завершена, то таймер создаст новый поток для выполнения задачи . Не так ли?


person M Sach    schedule 30.12.2013    source источник


Ответы (4)


В javadoc для Timer говорится

Каждому объекту Timer соответствует один фоновый поток, который используется для последовательного выполнения всех задач таймера.

По сути, он содержит очередь задач, к которой добавляется при планировании. Он использует один поток для перебора очереди и выполнения задач.

person Sotirios Delimanolis    schedule 30.12.2013
comment
но тогда в чем разница scheduleAtFixedRate и schedule? В моем примере они должны вести себя одинаково? - person M Sach; 30.12.2013
comment
@MSach Это в javadoc. schedule — с фиксированной задержкой, а scheduleatFixedRate — с фиксированной скоростью. Это влияет на время запуска запланированной задачи. - person Sotirios Delimanolis; 30.12.2013
comment
Согласно javadocs ScheduleAtFixedRate, каждое выполнение запланировано относительно запланированного времени выполнения начального выполнения. Если выполнение задерживается по какой-либо причине (например, сборка мусора или другая фоновая активность), два или более выполнения будут выполняться в быстрой последовательности, чтобы наверстать упущенное. что это значит? У меня создается впечатление, что если вторая задача должна быть выполнена, даже если первая задача не завершена, то таймер создаст новый поток для надлежащей задачи. Не так ли? - person M Sach; 30.12.2013
comment
@MSach Нет, нет другого потока, кроме потока Timer. Задания стоят в очереди. Если есть задержка, он просто будет ждать меньше времени между выполнениями. - person Sotirios Delimanolis; 30.12.2013
comment
@MSach То есть в случае фиксированной ставки. В случае фиксированной задержки следующее выполнение произойдет после задержки. - person Sotirios Delimanolis; 30.12.2013

Timer использует под капотом шаблон Active Object, поэтому используется только один поток, и планирование новой задачи по таймеру добавляет эту задачу в очередь задач потока.

Поток таймера отслеживает все задачи в своей очереди и бездействует до тех пор, пока не будет запланирована следующая задача. Затем он просыпается и выполняет саму задачу, напрямую вызывая task.run(), что означает, что он не порождает другой поток для выполнения кода.

Это также означает, что если вы запланируете выполнение двух задач одновременно, то в соответствии с шаблоном Active Object они будут выполняться последовательно (одна за другой) в одном и том же потоке управления. Это означает, что вторая задача будет выполняться после запланированного времени (но, вероятно, ненамного).

Теперь, чтобы однозначно ответить на ваш вопрос, вот логика планирования из Timer.class, которая планирует следующий раз, когда задача должна быть запущена снова (из строк 262-272 здесь):

// set when the next task should be launched
if (task.fixedRate) {
    // task is scheduled at fixed rate
    task.when = task.when + task.period;
} else {
    // task is scheduled at fixed delay
    task.when = System.currentTimeMillis()
            + task.period;
}

// insert this task into queue
insertTask(task);

task.fixedRate имеет значение true, если вы используете один из методов timer.scheduleAtFixedRate(), и значение false, если вы используете один из методов timer.schedule().

task.when — это «время» (такты), на которое было запланировано выполнение задачи.

task.period — это интервал, который вы передали методу timer.schedule*().

Итак, из кода мы видим, что если вы используете фиксированную скорость, то повторяющаяся задача будет запланирована для запуска относительно того, когда она была запущена впервые. Если вы не используете фиксированную скорость, то она будет выполняться относительно того времени, когда она выполнялась в последний раз (которая будет дрейфовать относительно фиксированной скорости, если ваша задача никогда не задерживается и для ее выполнения требуется менее одного тика).

Это также означает, что если задача отстает и выполняется с фиксированной скоростью, то Timer будет перепланировать задачу для немедленного выполнения до тех пор, пока она не догонит общее количество раз, которое она должна была выполняться за заданный период.

Итак, если у вас есть задача, скажем, ping(), которую вы планируете запускать с фиксированной частотой каждые 10 мс, и есть временная блокировка в методе ping(), где для выполнения требуется 20 мс, тогда Timer снова вызовет ping() сразу после предыдущего вызова. завершено, и это будет продолжаться до тех пор, пока не будет достигнута заданная скорость.

person Matt Klein    schedule 25.11.2014

Класс таймера создает один поток для каждого экземпляра класса таймера, и этот поток выполняет все запланированные задачи Timer#schedule или Timer#scheduleAtFixRate.

Итак, как вы заметили, таймер создает только один поток.

Задача должна была начаться до того, как завершалась предыдущая задача, после чего следующая задача ждала завершения предопределяющей задачи.

Таким образом, Timer «никогда» не создает еще один поток, хотя предыдущая задача еще не завершена и пришло время начать следующую задачу.

Итак, я советую вам следующее:
если вы хотите планировать задачи и выполнять их вовремя, независимо от того, завершена предыдущая задача или нет, используйте ScheduledThreadPoolExecutor вместо Timer.

И хотя, если вы не хотите, предпочтительнее использовать ScheduledThreadPoolExecutor, чем Timer, потому что, во-первых, задачи, запланированные Timer, никогда не выполнялись бы, если бы задача выдавала RuntimeException или Error.

person t_ozawa    schedule 30.12.2013

Расписание не будет выполнять пропущенную задачу, если время ее начала уже в прошлом. scheduleAtFixedRate будет выполнять пропущенные задачи, если время начала уже в прошлом. Для пропущенных задач время начала будет рассчитываться на основе времени окончания последней задачи. Когда пропущенные задачи будут выполнены полностью, время начала новых обычных задач будет рассчитываться на основе времени начала последней задачи.

БР Санчес

person Sanchelz    schedule 28.07.2016