Зацикливание потоков каждые 3 секунды в JavaFX - PullRequest
0 голосов
/ 15 февраля 2020

В настоящее время я работаю над приложением на фондовом рынке, которое время от времени меняет значения цен акций (в этом примере давайте изменяем значение акций каждые 3 секунды). Я изучал выполнение задач , но не мог найти способ, чтобы задачи выполнялись непрерывно. Есть ли способ сделать задачу l oop каждые 3 секунды в основном классе? (Для пояснения, я бы хотел, чтобы эта циклическая задача была добавлена ​​в тело моего основного метода, без использования внешних классов, кроме основного метода)

Вот что у меня так далеко:

Task<Void> change = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                try {
                    Thread.sleep(3000);
                } 
                catch (InterruptedException e) {}
                return null;
            }
        };
        change.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent event) {

            }
        });
        new Thread(change).start(); 

ПРИМЕЧАНИЕ. На этот код ссылается здесь

1 Ответ

3 голосов
/ 15 февраля 2020

Не думайте в терминах «постоянно» или «зацикливание». Вместо этого подумайте о том, какую работу нужно выполнить (посмотрите цены * 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...