首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Java中的多线程。同时倒计时和计时器

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

Stack Overflow用户
提问于 2018-06-12 06:46:31
回答 1查看 1.7K关注 0票数 0

当计时器和倒计时方法单独运行时,它们都可以工作。它们也作为两个单独的线程工作,但是线程序列的优先级导致倒计时和计时器(倒计时)不准确。

下面是输出示例: 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计时器完成,计时器应该继续,但是,当计时器和倒计时都处于活动状态时,线程应该以秒为单位跟踪时间,而不会失去准确性。目前,我依靠控制台来显示此计数,但是我将在图形界面中对此进行编程,以向用户显示倒计时和计时器。也许线程的执行需要在它们之间轮换,以便计时器均匀地进行,此外,它们应该同步,这样一个线程就不能在没有另一个的情况下继续执行。关于实现的任何提示。谢谢。

公共类控制台{

代码语言:javascript
复制
     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;
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-06-12 08:06:08

线程中的自由循环会给CPU带来相当大的负载,这可能会对其他线程产生不利影响。记住,更多的线程并不总是意味着更快地完成更多的工作。

所需要的是一些“让出”时间的方法,这样CPU就可以更好地调度其他线程。

由于您只对秒精度感兴趣,因此使用半秒的sleep是一个很好的起点。这大大减少了每个线程在CPU上所需的时间。

就我个人而言,在处理像这样的基于时间的解决方案时,我更喜欢使用date/time API,因为它通常会产生更好、更可靠的解决方案,但这就是我。

下面的示例简单地启动了10个线程,每个线程都有5秒的超时。每个线程在运行其规定的逻辑之前休眠半秒

代码语言:javascript
复制
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();
            }
        }
    }
}

这样产生的输出类似于...

代码语言:javascript
复制
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。线程将“滴答”计时器,这将允许它们确定它们已经运行了多长时间,以及它们是否已经过期,例如……

代码语言:javascript
复制
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,但仍然不是我最喜欢做的事情),并简单地循环“timer”列表,直到所有计时器都过期。

哪种解决方案更好?取决于你所处的环境。就我个人而言,我倾向于使用单个快速运行的线程(我倾向于使用Thread.sleep(5),但这只是我的情况),它可以迭代一系列“要做的事情”。在上面的例子中,因为我们依赖于基于时间的解决方案(而不是计数器),所以即使我们有一些滞后,我们仍然可以得到(合理地)准确的结果

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50807048

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档