Многопоточность в Java.Обратный отсчет и таймер одновременно - PullRequest
0 голосов
/ 12 июня 2018

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

Вот пример выходных данных: cookie 10 cookie 9 cookie 8 секунд 1 cookie 7 секунд 2 секунды 3 cookie 6 секунд 4 cookie 5 секунд 5 cookie 4 cookie 3 секунды 6 cookie 2 секунды 7 cookie 1 секунды 8 секунд 9секунды 10 секунд 11 секунд 12 секунд 13 секунд 14 секунд 15 секунд 16 секунд 17 секунд 18 секунд 19

После того, как таймер cookie завершен, таймер должен продолжаться, как это происходит, однако пока активны таймер и обратный отсчет, потоки должныотслеживать время в секундах без потери точности.В данный момент я полагаюсь на консоль для отображения этих подсчетов, однако я буду программировать это в графическом интерфейсе, который покажет пользователю обратный отсчет и таймер.Возможно, выполнение потоков должно чередоваться между ними, чтобы таймеры развивались одинаково, кроме того, они должны быть синхронизированы, чтобы один не мог продолжаться без другого.Любые советы по реализации.Спасибо.

Консоль общего класса {

     long lastTime;
     boolean counting = true;
     boolean cCounting = true;
     long seconds = 0;
     long delta = 0;
     volatile int startNumber = (int) Level.cookieTime / 1000;
    Thread countDown;
    Thread time;

    public Console() {

        counting = Game.enter;

        cookieCountDown();
        timer();
        lastTime = System.currentTimeMillis();
    }

    public void timer() {

        time = new Thread(new Runnable() {
            @Override
            public void run() {
                seconds = 0;


                while (true) {
                    try {
                        Thread.sleep(0);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    counting = Game.enter;

                    while (counting) {

                        long now = System.currentTimeMillis();
                        delta = now - lastTime;

                        if (delta >= 1000) {

                            delta = 0;
                            lastTime = System.currentTimeMillis();
                            System.out.println("seconds " + seconds); //Print seconds
                            seconds++;

                            if (!counting){
                                System.out.println("stoped"  + counting);
                                //time.stop();
                              //  return;
                            }
                        }
                    }
                }
            }

        });
        time.start();

    }

    public void cookieCountDown() {
        countDown = new Thread(new Runnable() {
            @Override
            public void run() {
                Player.cCounting = true;

                while (startNumber != 0) {
                    startNumber = (int) Level.cookieTime / 1000;
                    cCounting = Game.enter;

                    while (startNumber > 0 && cCounting) {
                        long now = System.currentTimeMillis();
                        delta = now - lastTime;

                        if (delta >= 1000) {
                            delta = 0;
                            lastTime = System.currentTimeMillis();
                            System.out.println("cookie " + startNumber);// print countdown;
                            startNumber--;

                            if (!Player.cCounting) {
                                Player.cCounting = true;
                                return;
                            }
                        }
                    }
                }
            }
        });
        countDown.start();

        if (startNumber == 0 || !Player.cCounting) {

            Player.cCounting = true;
            startNumber = (int) Level.cookieTime / 1000;

        }
    }


    public void setCounting(boolean counting) {
        this.counting = counting;
    }
}

1 Ответ

0 голосов
/ 12 июня 2018

Свободные циклы вращения в потоках создают значительную нагрузку на процессор, что может отрицательно сказаться на других потоках.Помните, что больше потоков не всегда означает, что больше работы выполняется быстрее.

Требуется какой-то способ «дать» время, чтобы процессор мог лучше планировать другие потоки.

Поскольку вас интересует только вторая точность, для начала лучше использовать полусекунду sleep.Это значительно сокращает время, необходимое каждому потоку на ЦП.

Лично, когда я имею дело с решениями, основанными на времени, я предпочитаю использовать API даты / времени, так как он обычно производит лучше и большенадежное решение, но это я.

В следующем примере просто запускается 10 потоков, каждый с 5-секундным таймаутом.Каждый поток спит в течение полсекунды, прежде чем пройти через предписанную ему логику

import java.time.Duration;
import java.time.Instant;
import java.util.Random;

public class Test {

    public static void main(String[] args) throws InterruptedException {
        new Test();
    }

    public Test() throws InterruptedException {
        Random rnd = new Random();
        for (int index = 0; index < 10; index++) {
            Thread t = new Thread(new Timeout(5, "Cookie " + index));
            t.start();
        }

        Thread.sleep(500);
    }

    public class Timeout implements Runnable {

        private Duration duration;
        private Instant startTime;
        private String label;

        public Timeout(int count, String label) {
            duration = Duration.ofSeconds(count);
            this.label = label;
        }

        @Override
        public void run() {
            long time = Long.MAX_VALUE;
            try {
                startTime = Instant.now();
                while (true) {
                    Duration runTime = Duration.between(startTime, Instant.now());
                    Duration remainingTime = duration.minus(runTime);
                    // You could also use remainingTime.getSeconds() == 0, but it
                    // depends on your desired level of accuracy
                    if (remainingTime.isNegative()) {
                        System.out.println("Out of time");
                        return;
                    } else {
                        if (time != remainingTime.getSeconds()) {
                            time = remainingTime.getSeconds();
                            System.out.println(label + " " + duration.getSeconds() + "/" + time);
                        }
                    }
                    Thread.sleep(500);
                }
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }
}

Это выдает результат, похожий на ...

Cookie 3 5/5
Cookie 4 5/5
Cookie 0 5/5
Cookie 1 5/5
Cookie 2 5/5
Cookie 6 5/5
Cookie 9 5/5
Cookie 5 5/5
Cookie 7 5/5
Cookie 8 5/5
Cookie 1 5/4
Cookie 5 5/4
Cookie 7 5/4
Cookie 6 5/4
Cookie 2 5/4
Cookie 0 5/4
Cookie 3 5/4
Cookie 4 5/4
Cookie 8 5/4
Cookie 9 5/4
//...
Cookie 5 5/1
Cookie 3 5/1
Cookie 0 5/1
Cookie 7 5/1
Cookie 1 5/1
Cookie 2 5/1
Cookie 6 5/1
Cookie 8 5/1
Cookie 4 5/1
Cookie 9 5/1
Cookie 5 5/0
Cookie 7 5/0
Cookie 4 5/0
Cookie 8 5/0
Cookie 0 5/0
Cookie 2 5/0
Cookie 3 5/0
Cookie 1 5/0
Cookie 6 5/0
Cookie 9 5/0
Out of time
Out of time
Out of time
Out of time
Out of time
Out of time
Out of time
Out of time
Out of time
Out of time

Другое решение может заключаться в использовании одного потока иList «таймеров».Поток «отметит» таймеры, что позволит им определить, как долго они работают и истек ли он или нет, например ...

import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Test {

    public static void main(String[] args) throws InterruptedException {
        new Test();
    }

    public Test() throws InterruptedException {
        List<Timeout> timers = new ArrayList<>(10);
        for (int index = 0; index < 10; index++) {
            timers.add(new Timeout(5, "Cookie " + index));
        }

        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    Iterator<Timeout> it = timers.iterator();
                    while (it.hasNext()) {
                        Timeout timer = it.next();
                        timer.tick();
                        if (timer.isTimedOut()) {
                            it.remove();
                        }
                    }
                    Thread.yield();
                    if (timers.isEmpty()) {
                        return;
                    }
                }
            }
        });
        t.start();
        Thread.sleep(500);
    }

    public class Timeout {

        private Duration duration;
        private Instant startTime;
        private String label;

        private Long lastTime;
        private boolean timedOut;

        public Timeout(int count, String label) {
            duration = Duration.ofSeconds(count);
            this.label = label;
        }

        public boolean isTimedOut() {
            return timedOut;
        }

        public void tick() {
            if (timedOut) {
                return;
            }
            if (startTime == null) {
                startTime = Instant.now();
            }
            Duration runTime = Duration.between(startTime, Instant.now());
            Duration remainingTime = duration.minus(runTime);
            // You could also use remainingTime.getSeconds() == 0, but it
            // depends on your desired level of accuracy
            if (remainingTime.isNegative()) {
                System.out.println("Out of time");
                timedOut = true;
            } else {
                if (lastTime == null || lastTime != remainingTime.getSeconds()) {
                    lastTime = remainingTime.getSeconds();
                    System.out.println(label + " " + duration.getSeconds() + "/" + lastTime);
                }
            }
        }
    }
}

Я мог бы даже добавить впара методов, чтобы вернуть «длительность» таймера, время работы и оставшееся время, но это я.

Недостатком этого является то, что если «основной» поток занимает слишком много времени,таймер может истечь до следующего цикла проверки.В приведенном выше примере я в основном позволил потоку работать максимально быстро (я добавил yield, но это не мое любимое занятие) и просто перебрал список «таймеров», пока всетаймеры истекли.

Какое решение лучше?Зависит от ваших обстоятельств.Лично я стремлюсь к одному быстро работающему потоку (я использую Thread.sleep(5), но это только я), который может перебирать серию «дел, которые нужно сделать».В приведенном выше примере, поскольку мы полагаемся на решения, основанные на времени (а не на счетчики), даже если у нас есть некоторое отставание, мы все равно получаем (достаточно) точный результат

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