3

在尝试学习如何创建延迟时,我研究并发现主要的答案是使用 Handler/Runnable/postDelayed。

                        Handler handler=new Handler();
                        final Runnable r = new Runnable()
                        {
                            public void run() 
                            {
                                delayedMethod();
                            }
                        };
                        handler.postDelayed(r, 1000);

这在一段时间内工作正常,但我添加了更多正在发生的事情,现在它们有时会以错误的顺序发生。

这组事件:

paintScreen1()
...
延迟PaintScreen2()
...
paintScreen3()

正在搞砸(有时)并这样做:

paintScreen1()
...
paintScreen3()
...
delayedPaintScreen2() (最后运行并被paintScreen3 的操作弄乱了)

似乎没有另一种创建延迟的好方法 - 一种不创建线程的方法。

我尝试过的解决方案以确保代码事件以正确的顺序运行:

0 将主进程放在一个大的同步块中。

1 在主进程中涉及的每个方法的方法名中加上 synchronized 关键字。

2 仅将同步关键字放在 Runnable 中的方法上。

3 拿走 Handler/Runnable/postdelayed 并替换为 handler.sendEmptyMessageDelayed(0,1000)

4 制作一个 Handler 实例变量,供每个 Handler/Runnable 块使用(与 Handler handler1、handler2、handler3 等相反)

5

                        Handler handler=new Handler();
                        final Runnable r = new Runnable()
                        {
                            public void run() 
                            {
                                waitOver = true;
                            }
                        };
                        handler.postDelayed(r, 1000);

                        while (waitOver == false) {

                        }
                        delayedMethod();
                        waitOver = false;

我的下一个尝试可能是尝试以某种方式使用 Thread 类,这样我就可以调用 thread.join()。我担心,如果失败了,接下来的事情将会非常漫长和复杂。

有什么建议么?

任何简单的解决方案示例?

谢谢

编辑:我可能对 Handler/Runnable 是否导致文字线程感到困惑。

编辑:这是一个游戏。用户移动,屏幕更新以显示移动,计算告诉他们得分,重新着色屏幕上的框,添加延迟以允许用户看到他们的点,然后调用方法以删除彩色方块,当该方法完成时我们返回调用它的方法(包含 Handler/runnable),代码继续向下调用另一个方法,导致棋盘的随机正方形变为紫色。所以它应该发生用户移动,重新绘制以显示得分,延迟以便用户可以看到得分,重新绘制以擦除方块,然后随机出现紫色方块。有时会发生什么(据我所知)是随机的紫色方块会在它应该执行之前执行,选择得分点的方块之一,干扰,

mainmethod() {
...
if (pointscored) {
squaresglow();
...
//延迟,以便用户可以在清理发生之前看到发光
Handler-runnable
cleanup(); 延迟} ...
PurpleSquare (); }



我希望这不会更加混乱。PurpleSquare 在清理之前运行,事情就搞砸了。

编辑:试过这个:6

                        CountDownLatch doneSignal = new CountDownLatch(1);
                        Handler handler=new Handler();
                        final LatchedRunnable lr = new LatchedRunnable(doneSignal);
                        handler.postDelayed(lr, COMPUTER_MOVE_DELAY);
                        try {
                            doneSignal.await();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }

                        class LatchedRunnable implements Runnable {
                            private final CountDownLatch doneSignal;

                            LatchedRunnable(CountDownLatch doneSignal) {
                                this.doneSignal = doneSignal;
                            }

                            public void run() {
                                 delayedProcess();
                                 doneSignal.countDown();                                                                                                                                                               
                            }
                        }    

7

                        ExecutorService executorService = Executors.newFixedThreadPool(5);
                        final CountDownLatch latch = new CountDownLatch(1);
                        executorService.execute(new Runnable() {
                            public void run() {
                                try {
                                    Looper.prepare();
                                    Handler handler=new Handler();
                                    final Runnable r = new Runnable()
                                    {
                                        public void run() 
                                        {
                                            delayedMethodCleanupCalc();
                                        }
                                    };
                                    handler.postDelayed(r, 4000);
                                } finally {
                                    latch.countDown();
                                }  
                            }
                        });
                        try {
                            latch.await();
                            delayedMethodPaintScreen();
                        } catch (InterruptedException e) {
                            // todo >> handle exception
                        }
4

1 回答 1

1

PurpleSquare 在清理之前运行,事情搞砸了

mainmethod() {
...
if (pointscored) {
    squaresglow();
    ...
    //delay so user can see the glow before the cleanup happens
    Handler-runnable
        cleanup();
    postdelayed
}
...
purpleSquare();
} 

你这里有一个设计缺陷。将处理程序视为消息队列,每当处理器决定处理消息时“稍后”将执行代码,并将 postDelayed 视为将该消息填充到队列底部的不精确方式。如果您调用 postDelayed 并且在当前方法中仍有几行代码要执行,那么这些行很有可能会在 postDelayed 消息被接收之前执行。

您要做的是确保在积分例程完成工作后调用purpleSquare(),这可能需要等待它完成。在这种情况下,您不应该对消息队列进行 PostDelaying。您应该使用的是信号量和 pointScored 线程。

考虑以下代码设计:

final Runnable pointScoredTask = new Runnable() {
    public synchronized void run() {
        try {
            squaresglow();
            //...
            Thread.sleep(2500); //2.5 sec before cleanup occurs
            cleanup();
        } catch (InterruptedException e) {
        }
        notify(); //make sure we call notify even if interrupted
    }
};
void mainmethod() {
    //...
    if (bPointWasScored) {
        synchronized (pointScoredTask) {
            try {
                Thread psThread = new Thread(pointScoredTask,"pointscored");
                psThread.start(); //thread will start to call run(), but we get control back to avoid race condition
                pointScoredTask.wait(6000); //wait no more than 6 sec for the notify() call
            } catch (InterruptedException e) {
            } 
        }
        //if a point was scored, nothing past this line will execute until scoreglow has been cleaned up 
    }
    //...
    purpleSquare();
    //...
}

我知道你宁愿避免使用线程,但是当你使用它们时,有些东西会更好地工作。试试上面的设计,看看是否能解决你看到的同步问题。

于 2012-08-30T17:46:47.753 回答