我有一个工作线程位于后台,处理消息。像这样的事情:
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
被读取后,没有办法确定工作线程已经分配给这个字段了!
我不能简单地创建Handler
来自Worker
的构造函数,因为构造函数运行在主线程上,所以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(...);
但这也不可靠:如果notifyAll()
发生在wait()
,那么我们就永远不会醒来了!
通过初始Message
to the Worker
的构造函数,具有run()
方法发布它。临时解决方案不适用于多条消息,或者如果我们不想立即发送但稍后发送。
忙着等待,直到handler
场不再是null
。是的,最后的手段...
我想创建一个Handler
and MessageQueue
代Worker
线程,但这似乎不可能。最优雅的方法是什么?
最终的解决方案(减去错误检查),感谢 CommonsWare:
class Worker extends HandlerThread {
// ...
public synchronized void waitUntilReady() {
d_handler = new Handler(getLooper(), d_messageHandler);
}
}
从主线程:
Worker worker = new Worker();
worker.start();
worker.waitUntilReady(); // <- ADDED
worker.handler.sendMessage(...);
这要归功于以下语义HandlerThread.getLooper()
它会阻塞直到循环器被初始化。
顺便说一句,这与我上面的解决方案 #1 类似,因为HandlerThread
大致实现如下(一定喜欢开源):
public void run() {
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Looper.loop();
}
public Looper getLooper() {
synchronized (this) {
while (mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
关键的区别在于它不检查工作线程是否正在运行,而是实际上创建了一个循环器;这样做的方法是将循环器存储在私有字段中。好的!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)