重新启动一个帖子 - 这是我的头脑

时间:2014-06-26 11:26:40

标签: java android multithreading

我有一个显示秒表的线程,比如减少时间。这个线程计数1分钟。在这一分钟内,用户必须回答一个问题。如果用户在完成一分钟之前回答问题,则向他显示下一个问题并且线程被重置为计数1分钟。

我面临的问题是,当我调用reStartTimeKeeper()时,计时器重新启动但开始计数更快。随后的每次调用都会进一步提高计数器的速度。我的意思是,在第一次调用reStartTimeKeeper()之后,我的timmer在30秒(大约)内计算60秒,在第二次调用reStartTimeKeeper()之后,我的timmer在15秒(大约)内计算60秒。等等。

原因是当我在reStartTimeKeeper()中设置Question_Time = -1时,线程的第一个实例被暂停。它不断执行while循环,就好像它正在等待while()中的条件变为true。

当我尝试启动线程的第二个实例时,我设置Question_Time = 60。这将启动线程的新实例。这样做也可以激活休眠的第一个实例,它等待条件变为真。

我只想在任何时刻获得我的线程的一个实例。我把它变成了一个静态变量。这样做也没有效果。

        int Question_Time=-1;
        static Thread timeKeeper;
        Handler mHandler = new Handler();
        void Start_TimeKeeper()
        {
                Question_Time=60;
            timeKeeper = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (Question_Time!=-1) 
                    {
                        mHandler.post(new Runnable() 
                        {
                            @Override
                            public void run() 
                            {
                                Question_Time--;
                                UpdateUI();
                            }
                        });

                        try 
                        {
                            Thread.sleep((1000));
                        } 
                        catch (InterruptedException e) 
                        {

                            e.printStackTrace();
                        }
                    }
                }
            });
            timeKeeper.start();
        }

void reStartTimeKeeper()
{
Question_Time=0;
while(Question_Time==-1);
Start_TimeKeeper();
}

如果有人可以同步这个流程,那就太好了! 如果你发现任何愚蠢的事情或一些改进的建议,那将是非常受欢迎的。 谢谢!

当我尝试启动线程的第二个实例时,我设置Question_Time = 60。这将启动线程的新实例。并且这样做也激活休眠的第一个实例,它等待条件变为真。我想完全杀死线程的第一个实例,当它被杀死时,我想安全地重新启动新的实例。

2 个答案:

答案 0 :(得分:1)

当你致电Start_TimeKeeper();时,它会启动另一个线程而不会停止第一个线程。所以你的两个线程减少了时间。这就是它计算速度更快的原因。

不是每次都创建一个新线程,而是只检查旧线程是否已完成,如果是,请启动一个新线程,否则只需重置Question_Timeint


class TimeKeeper extends Thread {

    private volatile boolean run = false;

    @Override
    public void run() {
        run=true;//run while run=true
        while (run) {
            if (Question_Time >= 0) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Question_Time--;
                        UpdateUI();
                    }
                });
            }
            try {
                Thread.sleep(Question_Time >= 0 ? 1000 : 5000);//loop with longer delays if question time is below zero
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void finish() {
        run = false;
    }

}

使用此TimeKeeper类。启动一次,每次都使用,重置变量重启。

答案 1 :(得分:0)

两个主要问题(除了整个方法的概念问题):

  1. 没有同步。正如安迪在评论中所说:

    1. 重置时间管理员称为
    2. 重置将时间设置为0
    3. 时间管理员将时间设置为-1
    4. 重置进入循环
    5. 重置将时间设置为60
    6. 时间管理员进入下一个循环迭代
    7. 重置创建辅助时间管理员
    8. PROFIT! (两个平行的时间守护者)。
  2. 内存可见性。时间是非易失性原语。无法保证线程中的while实际上看到剩余的最新时间值。

  3. 通过在你剩下的时间内使用一个原子变量可以缓解这两个问题(并且对你如何使用它进行了一些思考,只需要调用.get()到本地var就不会起作用了。 / p>

    更好的方法是不要产生这么多线程。使用一个无限循环的单个时间线程,当设置一个布尔标志时 - 递减计数器。

    如果您仍想生成线程并正确杀死它们 - 这应该有所帮助:Stop, interrupt, suspend and resume a java thread