简体   繁体   English

Java中的多线程。 同时倒数和计时器

[英]Multi threading in Java. Countdown and timer both at once

Both the timer and the countdown method work when they are run individually. 分别运行计时器和倒数计时方法都可以。 They also work as two individual threads however the priority of the thread sequences is causing the count down and the timer(counting up) not to be accurate. 它们也作为两个单独的线程工作,但是线程序列的优先级导致倒数和计时器(递增)不准确。

Here is the sample output:cookie 10 cookie 9 cookie 8 seconds 1 cookie 7 seconds 2 seconds 3 cookie 6 seconds 4 cookie 5 seconds 5 cookie 4 cookie 3 seconds 6 cookie 2 seconds 7 cookie 1 seconds 8 seconds 9 seconds 10 seconds 11 seconds 12 seconds 13 seconds 14 seconds 15 seconds 16 seconds 17 seconds 18 seconds 19 以下是示例输出: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

Once the cookie timer is done the timer should continue as it does however while both timer and countdown are active the threads should keep track of the time in seconds without loosing accuracy. 一旦完成了cookie计时器,计时器应继续运行,但是在计时器和倒计时都处于活动状态时,线程应以秒为单位跟踪时间,而不会降低准确性。 At the moment I am relying on the console to display this counts however I will be programming this in a graphical interface that will show the user the countdown and timer. 目前,我依靠控制台显示此计数,但是我将在图形界面中对此进行编程,以向用户显示倒数和计时器。 Perhaps execution of the threads need to alternate between them in order for the timers to progress equally, in addition they should be synchronized so that one can not continue without the other. 也许线程的执行需要在它们之间交替进行,以使计时器相等地运行,此外,还应该同步它们,以便一个线程不能没有另一个线程继续下去。 Any tips on implementation. 有关实施的任何提示。 Thanks. 谢谢。

public class Console { 公共类控制台{

     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;
    }
}

Free wheeling loops in threads puts a considerable load on the CPU which can have an adverse affect on other threads. 线程中的自由循环会给CPU带来相当大的负担,这可能会对其他线程产生不利影响。 Remember, more threads doesn't always mean more work gets done faster. 请记住,更多线程并不总是意味着更快地完成更多工作。

What's needed is some way to "yield" time, so the CPU can better schedule other threads. 所需要的是某种“屈服”时间的方法,以便CPU可以更好地调度其他线程。

Since you're only interested in a second accuracy, using a sleep of half a second is a good place to start. 由于您只对秒精度感兴趣,因此使用半秒sleep是一个不错的起点。 This greatly reduces the amount of time that each threads needs on the CPU. 这大大减少了每个线程在CPU上所需的时间。

Personally, when dealing with time based solutions like this, I prefer to use the date/time API, as it generally produces a better and more reliable solution, but that's me. 就个人而言,在处理诸如此类的基于时间的解决方案时,我更喜欢使用日期/时间API,因为它通常会产生更好,更可靠的解决方案,但这就是我。

The following example simply starts 10 threads, each with a 5 second timeout. 下面的示例仅启动10个线程,每个线程有5秒的超时。 Each thread sleeps for half a second before running through it's prescribed logic 每个线程在运行其规定的逻辑之前睡眠半秒

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();
            }
        }
    }
}

This produced an output similar to... 这样产生的输出类似于...

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

Another solution might be to use a single thread and a List of "timers". 另一个解决方案可能是使用单个线程和“计时器” List The thread would "tick" the timers, which would allow them to determine how long they've been running and it they have expired or not, for example... 线程将“勾选”计时器,这将使它们可以确定运行了多长时间以及它们是否到期,例如...

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);
                }
            }
        }
    }
}

I might even add in a couple of methods to return the "duration" of the timer, the running time and the amount of time remaining, but that's me. 我什至可以添加一些方法来返回计时器的“持续时间”,运行时间和剩余时间,但这就是我。

The drawback to this is, if the "main" thread takes too long, a timer could expire before the next check cycle. 这样做的缺点是,如果“主”线程花费的时间太长,则计时器可能在下一个检查周期之前到期。 In the above example, I've basically allowed the thread to run as fast as possible (I did add a yield , but still not my favourite thing to do) and simply looped through the list of "timer"s until all the timers had expired. 在上面的示例中,我基本上允许线程尽可能快地运行(我确实添加了yield ,但仍然不是我最喜欢的事情),并简单地循环遍历“计时器”列表,直到所有计时器都过期。

Which solution is better? 哪种解决方案更好? Depends on your circumstances. 取决于您的情况。 Personally, I tend to aim for a single fast running thread (I tend to use Thread.sleep(5) , but that's just me) which can iterate over a series of "things to be done". 就我个人而言,我倾向于针对一个快速运行的线程(我倾向于使用Thread.sleep(5) ,但那只是我自己),它可以迭代一系列“要完成的事情”。 With the above example, because we're relying on time based solutions (and not counters), even if we have some lag, we're still getting a (reasonably) accurate result 在上面的示例中,因为我们依赖于基于时间的解决方案(而不是计数器),所以即使我们有一些滞后,我们仍然可以获得(合理地)准确的结果

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM