Не думайте в терминах «постоянно» или «зацикливание». Вместо этого подумайте о том, какую работу нужно выполнить (посмотрите цены * sh на акции) и как часто вы хотите, чтобы эта задача выполнялась.
Для первой части вашей задачи определите Runnable
(или Callable
). Это означает просто наличие run
метода для соответствия контракту интерфейса.
В лямбда-синтаксисе:
Runnable runnable =
() -> {
System.out.println( "Looking up fresh stock prices at " + Instant.now().toString() ) ;
}
;
Далее, изучите фреймворк Executors, встроенный в современный Java. См. Oracle Учебное пособие . Эта структура значительно упрощает сложную работу по планированию потоков.
В частности, вы хотите использовать ScheduledExecutorService
. Этот интерфейс предназначен для планирования запуска задачи один раз в определенное время c (фактически, запуск один раз после истечения указанной задержки c), или повторного запуска задачи. Вы, конечно, хотите последнее.
Получите реализацию из класса Executors
. Для ваших нужд нам нужен только один поток. В других случаях вы можете использовать пул потоков.
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor() ;
У вас есть два варианта планирования: scheduleAtFixedRate
и scheduleWithFixedDelay
, Изучите их оба, чтобы решить, что лучше для вашего случая. В любом случае знайте, что вы не можете полностью полагаться на планирование. Ваша хост-ОС контролирует предоставление доступа к ядрам ЦП JVM, и JVM может манипулировать множеством потоков. Таким образом, время может быть отложено время от времени, хотя для большинства бизнес-приложений задержки должны быть незначительными.
ses.scheduleWithFixedDelay( runnable , 0L , 3L , TimeUnit.SECONDS ) ;
Возможно, вы захотите захватить возвращенный объект ScheduledFuture
, чтобы отслеживать ход или завершение , Наша строка кода выше игнорирует ее.
ВАЖНО Обязательно корректно завершите работу службы исполнителя, когда она больше не нужна, или когда ваше приложение закрывается. В противном случае ваши потоки могут продолжать работать в фоновом режиме, пережив выход из приложения.
ВАЖНО Оберните задачу внутри задачи Runnable
с помощью try-catch. Любое исключение или ошибка, которые появляются до уровня объекта Runnable, приведут к тому, что ваша служба-исполнитель будет молча завершена. Никаких дальнейших звонков не будет запланировано. Поиск переполнения стека, чтобы узнать больше.
Runnable runnable =
( ) -> {
try
{
System.out.println( "Looking up fresh stock prices at " + Instant.now().toString() );
}
catch ( Exception e )
{
// … try to recover, if you want the scheduled executor service to continue scheduling this task.
// Or, at least, do logging/notifications to know when and why the scheduling of this task halted.
e.printStackTrace();
}
};
ВАЖНО Никогда доступ / изменение любого виджета пользовательского интерфейса из фонового потока при использовании каркасов пользовательского интерфейса, таких как JavaFX , Swing или Vaadin . Каждая структура пользовательского интерфейса предоставит свой собственный механизм, с помощью которого вы можете запланировать работу по обновлению виджета, которая будет выполняться в потоке пользовательского интерфейса . Я не знаком с JavaFX, поэтому я не могу быть более конкретным c.
Соберите все это вместе в этом примере кода. А для тех, кому не нравится лямбда-синтаксис, используйте анонимный класс для нашего Runnable
.
package work.basil.example;
import java.time.Instant;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Bogus
{
public static void main ( String[] args )
{
Runnable runnable =
new Runnable()
{
@Override
public void run ( )
{
try
{
System.out.println( "Looking up fresh stock prices at " + Instant.now().toString() );
}
catch ( Exception e )
{
// … try to recover, if you want the scheduled executor service to continue scheduling this task.
// Or, at least, do logging/notifications to know when and why the scheduling of this task halted.
e.printStackTrace();
}
}
};
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ses.scheduleWithFixedDelay( runnable , 0L , 3L , TimeUnit.SECONDS );
try
{
Thread.sleep( TimeUnit.MINUTES.toMillis( 1 ) );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
finally
{
ses.shutdown(); // IMPORTANT Always shutdown gracefully your executor service so the thread pool does not outlive your app.
}
System.out.println( "INFO - Completed run at: " + Instant.now() );
}
}
При запуске.
Просмотр цены на акции sh в 2020-02-15T06: 35: 35.987199Z
Просмотр программы sh цены на акции в 2020-02-15T06: 35: 39.026132Z
поиск цены на акции sh цены на акции на 2020-02-15T06: 35: 42.030302Z
поиск цены sh цены на акции в 2020-02-15T06: 35: 45.035176Z
…
Просмотр вверх sh цены на акции в 2020-02-15T06: 36: 30.097743Z
Просмотр курса sh цены на акции в 2020-02-15T06: 36: 33.100713Z
ИНФОРМАЦИЯ - Завершено в: 2020-02-15T06: 36: 35.988752Z
Как уже упоминалось выше, обратите внимание, что задачи не точно три секунды, но довольно близко. Этот пример был запущен на Ma c mini с 6 реальными ядрами и без гиперпоточности, 32 гигабайта памяти, на MacOS Mojave, с Java 13.