简体   繁体   English

Worker / Background线程“ smothers” UI线程Android-为什么?

[英]Worker/Background Thread “smothers” UI thread Android- Why?

So when running the following method in doInBackground() inside of AsyncTask derived class: 因此,在AsyncTask派生类内部的doInBackground()中运行以下方法时:

void waitUntilButtonClicked(){
            while(true){
            synchronized (buttonClicked){
                if(buttonClicked) return;
                                        }
                try{Thread.sleep(1);} catch(InterruptedException e){};

                             }

without the very last line of code which makes the background thread sleep for 1 ms, the User Interface doesn't work (there is an EditText widget which when tapped on doesn't respond at all). 如果没有最后一行代码使后台线程休眠1 ms,则用户界面将不起作用(有一个EditText小部件,当点击该按钮时根本不响应)。 I should mention that when waitUntilButtonClicked() runs the UI thread doesn't run anything (or rather not any of my code). 我应该提到的是,当waitUntilButtonClicked()运行时,UI线程不会运行任何东西(或者不是我的任何代码)。

My problem is that I HAD to add the last line for everything to work. 我的问题是我不得不为所有工作添加最后一行。 I thought that a background thread cannot block the UI thread unless there is a huge error on the programmer's part. 我以为后台线程不能阻止UI线程,除非程序员方面有很大的错误。 Why does it happen? 为什么会发生? And yes I've figured out a 'way' to overcome that, is my solution a common method of doing that? 是的,我已经找到了解决该问题的“方法”,我的解决方案是这样做的常用方法吗? Is there a better way? 有没有更好的办法?

Why does it happen? 为什么会发生?

You are tying up the CPU in a busy spin loop , starving everything else of CPU cycles. 您正在忙碌的旋转循环中占用CPU,从而耗尽了CPU周期的所有其他时间。

And yes I've figured out a 'way' to overcome that, is my solution a common method of doing that? 是的,我已经找到了解决该问题的“方法”,我的解决方案是这样做的常用方法吗?

No, as sleeping to make a busy spin loop less busy generally is considered to be poor form . 不,因为睡觉使忙碌的自旋循环不那么忙,通常被认为是不良的形式

Is there a better way? 有没有更好的办法?

Let's assume, given your code, that you have a Button , and when the Button is clicked, you want to do work in a background thread. 让我们假设,在给定代码的情况下,您拥有一个Button ,并且在单击Button时,您想要在后台线程中工作。

If that is the case, you could: 如果是这样,您可以:

  • Only fork the thread once the Button is clicked, in the onClick() for the Button 只有用叉子叉线,一旦Button被点击时,在onClick()Button

  • Maintain a thread pool (eg, Executors.newSingleThreadExecutor() ), and post a job to that thread pool in the onClick() for the Button 维护一个线程池(例如Executors.newSingleThreadExecutor() ),然后在ButtononClick()中将作业发布到该线程池中

  • Use startService() to kick off an IntentService in the onClick() for the Button , where the IntentService does the work in onHandleIntent() (which is called on a background thread) 使用startService()ButtononClick()启动一个IntentService ,其中IntentServiceonHandleIntent()中进行工作onHandleIntent()在后台线程上调用)

  • Use a HandlerThread and post() events to it from onClick() for the Button 使用HandlerThread并将onClick()中的post()事件添加到该Button

  • Use mid-level blocking mechanisms, like CountDownLatch or Semaphore , where you trigger your background thread that way instead of via the boolean 使用中级阻止机制,例如CountDownLatchSemaphore ,在其中以这种方式触发后台线程,而不是通过boolean

  • Use seriously low-level blocking mechanisms, like Object#wait() 使用严重的低级阻止机制,例如Object#wait()

Probably there are other options as well, but those six would be a good starting point. 也许还有其他选择,但是那六个是一个很好的起点。 All of these cases use OS-level blocking primitives to mark a thread as suspended until necessary, rather than your approach of waking up the thread unnecessarily every millisecond. 所有这些情况都使用OS级阻塞原语来将线程标记为已暂停,直到必要为止,而不是使用您不必要地每毫秒唤醒一次线程的方法。

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

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