处理器/ Runnable的延迟产生的不同步,有时事件 [英] Handler/Runnable delays producing events that are out of sync sometimes

查看:486
本文介绍了处理器/ Runnable的延迟产生的不同步,有时事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在努力学习如何创建一个延迟我研究后发现的主要答案是使用处理器/ Runnable接口/ postDelayed。

 处理程序处理程序=新的处理程序();
                        最终的Runnable R =新的Runnable()
                        {
                            公共无效的run()
                            {
                                delayedMethod();
                            }
                        };
                        handler.postDelayed(R,1000);

这一段时间的工作确定,但我增加了一些更多的东西怎么回事,现在他们有时会以错误的顺序发生。

这组事件:

paintScreen1()结果
...结果
delayedPaintScreen2()结果
...结果
paintScreen3()

被拧紧了(有时),并这样做:

paintScreen1()结果
...结果
paintScreen3()结果
...结果
delayedPaintScreen2()(跑最后一棒,并得到由paintScreen3的行动搞砸)

似乎没有要创建延迟另一个好办法 - 一个不创建线程

我的解决方案,以使正确的顺序运行确保code事件曾尝试:

0将一个大的synchronized块内部的主要过程。

1把synchronized关键字在每一个参与的主要工艺方法的方法名。

2把synchronized关键字仅在Runnable接口的方法。

3带走处理器/ Runnable接口/ postdelayed和handler.sendEmptyMessageDelayed更换(0,1000)

4制作一个处理程序实例变量,通过每一个处理器/ Runnable接口块中使用(而不是处理程序handler1,handler2,handler3等)

5

 处理程序处理程序=新的处理程序();
                        最终的Runnable R =新的Runnable()
                        {
                            公共无效的run()
                            {
                                waitOver = TRUE;
                            }
                        };
                        handler.postDelayed(R,1000);                        而(waitOver == FALSE){                        }
                        delayedMethod();
                        waitOver = FALSE;

我的下一个尝试可能会尝试使用Thread类不知何故,所以我可以调用的Thread.join()。
如果失败,接下来的事情会很长且复杂,我怕。

有什么建议?

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

感谢

编辑:我可能会混淆是否处理器/ Runnable的结果字面线程与否

编辑:这是一场游戏。用户进行移动,屏幕更新以显示移动,计算告诉他们拿下一分,重新着色屏幕上的箱子,增加延迟,让用户看到他们的观点,然后调用方法来去除彩色方块,当该方法完成,我们回到调用它(包含处理程序/可运行)时,code继续下降到一个点,它调用导致被打开紫色电路板的随机方形的另一种方法的方法。因此,它应该发生用户移动,重新绘制显示点得分,延迟,以便用户可以看到点得分,以重绘擦除广场,然后随机紫色方形发生。有时会发生什么(只要我可以告诉)是随机紫方将执行之前,应该选择点在哪里进行评分,干扰的广场之一,而且做起来很清理方法会产生混乱而无法清除。

mainmethod(){结果
...结果
如果(pointscored){结果
   squaresglow();结果
...结果
//延迟,以便用户可以看到辉光清理结果发生之前
处理器可运行结果
清理(​​);结果
postdelayed结果
}结果
...结果
purpleSquare();结果
}

我希望这不是更加混乱。 purpleSquare运行清理和事情变得一团糟了。

编辑:
尝试这样:
6

  CountDownLatch doneSignal =新CountDownLatch(1);
                        处理程序处理程序=新的处理程序();
                        最后LatchedRunnable LR =新LatchedRunnable(doneSignal);
                        handler.postDelayed(LR,COMPUTER_MOVE_DELAY);
                        尝试{
                            doneSignal.await();
                        }赶上(InterruptedException的E){
                            // TODO自动生成catch块
                            e.printStackTrace();
                        }                        类LatchedRunnable实现Runnable {
                            私人最终CountDownLatch doneSignal;                            LatchedRunnable(CountDownLatch doneSignal){
                                this.doneSignal = doneSignal;
                            }                            公共无效的run(){
                                 delayedProcess();
                                 doneSignal.countDown();
                            }
                        }

7

  ExecutorService的ExecutorService的= Executors.newFixedThreadPool(5);
                        最终CountDownLatch闩=新CountDownLatch(1);
                        executorService.execute(新的Runnable(){
                            公共无效的run(){
                                尝试{
                                    尺蠖prepare()。
                                    处理程序处理程序=新的处理程序();
                                    最终的Runnable R =新的Runnable()
                                    {
                                        公共无效的run()
                                        {
                                            delayedMethodCleanupCalc();
                                        }
                                    };
                                    handler.postDelayed(R,4000);
                                } {最后
                                    latch.countDown();
                                }
                            }
                        });
                        尝试{
                            latch.await();
                            delayedMethodPaintScreen();
                        }赶上(InterruptedException的E){
                            // TODO>>处理异常
                        }


解决方案

  

purpleSquare运行清理,事情就会上当受骗之前

  mainmethod(){
...
如果(pointscored){
    squaresglow();
    ...
    //延迟,以便用户可以看到辉光清理发生之前
    处理器可运行
        清理(​​);
    postdelayed
}
...
purpleSquare();
}


您在这里有一个设计缺陷。处理程序看作将执行code后来,每当处理器决定来处理邮件和postDelayed作为一个不精确的方式来的东西,消息在队列的底部消息队列。如果你打电话postDelayed,你还有code左线执行当前方法,机会是非常好的被连收postDelayed消息之前的那些行会执行。

你所要做的就是确保purpleSquare()被调用的pointscored例行做了之后它的工作,这可能需要等待它完成。 PostDelaying到消息队列不应该在这种情况下做什么。你应该使用一个信号量和pointScored线程。

考虑以下code设计:

 最后的Runnable pointScoredTask =新的Runnable(){
    公共同步无效的run(){
        尝试{
            squaresglow();
            // ...
            视频下载(2500); //2.5秒之前发生的清理
            清理(​​);
        }赶上(InterruptedException的E){
        }
        通知(); //确保我们调用notify即使中断
    }
};
无效mainmethod(){
    // ...
    如果(bPointWasScored){
        同步(pointScoredTask){
            尝试{
                螺纹psThread =新主题(pointScoredTaskpointscored);
                psThread.start(); //线程将开始调用run()的,但我们得到控制返回,以避免竞争条件
                pointScoredTask.wait(6000); //等待不超过6秒的通知()调用
            }赶上(InterruptedException的E){
            }
        }
        //如果一个点进行评分,没有过去,这行会执行,直到scoreglow已清理
    }
    // ...
    purpleSquare();
    // ...
}

我知道你宁愿避免线程,但也有一些事情,只是工作更好,当你使用它们。试试上面的设计,看看是否可以算出你看到同步问题。

When trying to learn how to create a delay I researched and found the dominant answer to be to use Handler/Runnable/postDelayed.

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

That worked ok for a while, but I've added a few more things going on and now they are sometimes happening in the wrong order.

This set of events:

paintScreen1()
...
delayedPaintScreen2()
...
paintScreen3()

is screwing up (sometimes) and doing this:

paintScreen1()
...
paintScreen3()
...
delayedPaintScreen2() (runs last and gets messed up by the actions of paintScreen3)

There doesn't seem to be another good way to create delays - one that doesn't create threads.

Solutions I have tried in order to make sure the code events run in the proper order:

0 Putting the main process inside one big synchronized block.

1 Putting the synchronized keyword in the method name of every method involved in the main process.

2 Putting the synchronized keyword only on the method in the Runnable.

3 Taking away the Handler/Runnable/postdelayed and replacing with handler.sendEmptyMessageDelayed(0,1000)

4 Making one Handler instance variable, used by every Handler/Runnable block (as opposed to Handler handler1, handler2, handler3, etc.)

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;

My next attempt may be to try to used the Thread class somehow so I can call thread.join(). When that fails the next thing will be very long and complicated, I fear.

Any suggestions?

Any simple examples of a solution?

Thanks

Edit: I may be confused about whether Handler/Runnable results in literal threading or not.

Edit: It's a game. User makes a move, screen updated to show the move, calculation tells that they scored a point, recolor the boxes on the screen, add delay to allow user to see their point, then call method to removed colored squares, when that method completes and we return to the method that called it (containing the Handler/runnable), the code continues down to a point where it calls another method that results in a random square of the board being turned purple. So it should happen user-move, repaint to show point scored, delay so user can see point scored, repaint to erases squares, then random purple square happens. Sometimes what will happen (as far as I can tell) is the random purple square will execute before it should, choose one of the squares where the point was scored, interfere, and make it so the cleanup method gets confused and fails to cleanup.

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

I hope this is not even more confusing. purpleSquare runs before cleanup and things get screwed up.

Edit: Tried this: 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
                        }

解决方案

purpleSquare runs before cleanup and things get screwed up

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

You have a design flaw here. Think of Handlers as a queue of messages that will execute code "later" whenever the processor decides to process messages and postDelayed as an inexact way to stuff that message at the bottom of the queue. If you call postDelayed and you still have lines of code left in the current method to execute, chances are very good that those lines will execute before postDelayed messages are even received.

What you are trying to do is to make sure purpleSquare() gets called after the pointscored routine has done it's job, which may require waiting for it to finish. PostDelaying to the message queue is not what you should be doing in this case. What you should be using is a semaphore and a pointScored thread.

Consider the following code design:

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

I know you'd rather avoid threads, but there are some things that just work much better when you use them. Try the above design and see if that works out the synchronization issues you were seeing.

这篇关于处理器/ Runnable的延迟产生的不同步,有时事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆