我有一个后台工作线程,用于处理消息。类似于这样:
class Worker extends Thread {
public volatile Handler handler; // actually private, of course
public void run() {
Looper.prepare();
mHandler = new Handler() { // the Handler hooks up to the current Thread
public boolean handleMessage(Message msg) {
// ...
}
};
Looper.loop();
}
}
我想从主线程(UI线程,这并不重要)做出如下操作:
Worker worker = new Worker();
worker.start();
worker.handler.sendMessage(...);
问题在于,这会导致一个美丽的竞态条件:当读取worker.handler
时,无法确定工作线程是否已将其分配给该字段!
我不能简单地从Worker
的构造函数创建Handler
,因为构造函数在主线程上运行,所以Handler
会将自己关联到错误的线程。
这似乎并不是一个罕见的情况。我可以想出几种解决方法,但它们都很丑陋:
类似于以下内容:
class Worker extends Thread { public volatile Handler handler; // actually private, of course public void run() { Looper.prepare(); mHandler = new Handler() { // the Handler hooks up to the current Thread public boolean handleMessage(Message msg) { // ... } }; notifyAll(); // <- ADDED Looper.loop(); } }
并且来自主线程:
Worker worker = new Worker(); worker.start(); worker.wait(); // <- ADDED worker.handler.sendMessage(...);
但这也不是很可靠:如果在
wait()
之前发生了notifyAll()
,那么我们就永远不会被唤醒!将初始的
Message
传递给Worker
的构造函数,并让run()
方法发布它。这是一种临时的解决方案,无法用于多个消息,或者如果我们不想立即发送消息,而是稍后再发送。忙等待,直到
handler
字段不再为null
。 是的,这是最后的手段...
我想代表Worker
线程创建一个Handler
和MessageQueue
,但似乎不可能实现。有没有更优雅的方法?
HandlerThread
的特殊原因吗? - CommonsWaregetLooper()
方法会阻塞直到我们有一个Looper
,然后我们可以在主线程中使用new Handler(worker.getLooper())
来初始化Handler
。这样就解决了问题,对吧? - ThomasHandlerThread
如何适用于你的“工作器”模式。毕竟,这是你的问题和解决方案的实现--我只是指出一个帮助类来解决问题。你会比我更好地解释清楚。 - CommonsWare