因此,当在AsyncTask派生类内部的doInBackground()中运行以下方法时:
void waitUntilButtonClicked(){
while(true){
synchronized (buttonClicked){
if(buttonClicked) return;
}
try{Thread.sleep(1);} catch(InterruptedException e){};
}
如果没有让后台线程睡眠1毫秒的最后一行代码,用户界面就无法工作(有一个EditText小部件,当点击它时根本没有响应)。我应该提到,当waitUntilButtonClicked()运行时,UI线程不会运行任何东西(或者更确切地说,不会运行我的任何代码)。
我的问题是,我必须添加最后一行才能使所有内容都工作。我认为后台线程不能阻塞UI线程,除非程序员出现了巨大的错误。为什么会发生这种情况?是的,我已经找到了克服这一问题的"方法",我的解决方案是一种常见的方法吗?有更好的方法吗?
为什么会发生这种情况?
您将CPU占用在繁忙的旋转循环中,使其他一切都失去了CPU周期。
是的,我已经找到了克服这一问题的"方法",我的解决方案是一种常见的方法吗?
不,因为睡眠使繁忙的旋转循环不那么繁忙通常被认为是糟糕的形式
有更好的方法吗?
让我们假设,给定您的代码,您有一个Button
,当单击Button
时,您希望在后台线程中进行工作。
如果是这样的话,你可以:
-
在
Button
的onClick()
中,单击Button
后仅分叉线程 -
维护一个线程池(例如,
Executors.newSingleThreadExecutor()
),并将作业发布到onClick()
中的该线程池中,用于Button
-
使用
startService()
为Button
启动onClick()
中的IntentService
,其中IntentService
在onHandleIntent()
(在后台线程上调用)中执行工作 -
对于
Button
,从onClick()
向其使用HandlerThread
和post()
事件 -
使用中级阻塞机制,如
CountDownLatch
或Semaphore
,以这种方式触发后台线程,而不是通过boolean
-
认真使用低级别的阻塞机制,如
Object#wait()
也许还有其他选择,但这六个选择将是一个很好的起点。所有这些情况都使用操作系统级别的阻塞原语将线程标记为挂起,直到有必要为止,而不是每毫秒不必要地唤醒线程。