一、Looper的两点疑问
1) 问题一:Looper.loop()是处理消息,所有消息or部分消息?
2) 问题二:处理完消息后,结束or等待?
Android官方示例文档代码:
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }
看看Looper的源码就知道了:
public class Looper {
public static void prepare() {
…//初始化消息队列
}
public static void loop() {
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
return;
}
//处理这条消息
msg.target.dispatchMessage(msg);
}
}
}
public void quit() {
Message msg = Message.obtain();
//发送一条消息。消息的内容为空。
mQueue.enqueueMessage(msg, 0);
//loop()在处理到空消息时,会结束自己。
}
}
分析源码得知:
1) Looper. prepare()是初始化消息队列。
2) Looper.loop()是处理所有消息。
while(true)是一个死循环,循环处理所有消息。处理完所有的消息后,依然是死循环,等待新消息的到来。
解锁的唯一条件是:从队列里取出一条消息,消息的目标为空。
3) Looper.quit()是构造一个空内容的消息,放进队列中。实质就是结束处理消息。
二、GLSurfaceView的队列事件处理
问题一:GLSurfaceView一帧处理所有消息or部分消息?
问题二:事件队列,对帧率有影响吗?
看看GLSurfaceView的源码:
public class GLSurfaceView extends SurfaceView
implements SurfaceHolder.Callback {
//插入事件队列
public void queueEvent(Runnable r) {
mGLThread.queueEvent(r);
}
//线程中的循环逻辑
private void guardedRun(){
while (true) {//onDrawFrame的循环
while (true) {//处理消息的循环
if (! mEventQueue.isEmpty()) {
event = mEventQueue.remove(0);
break;
}
…
if (event != null) {
event.run();
event = null;
continue;
}
}//end 处理消息的循环
…
mRenderer.onDrawFrame(gl);
}
}
//内部类,线程
class GLThread extends Thread {
GLThread(Renderer renderer) {
}
@Override
public void run() {
guardedRun();
}
public void queueEvent(Runnable r) {
mEventQueue.add(r);
}
}
}
分析源码得知:
1) 一次会处理所有消息。
2) 只要队列里存在消息,onDrawFrame()就得不到执行的机会。所以,消息队列对帧率影响很大, 随便一条新到的消息,优先级都比onDrawFrame高。
三、Java线程中的wait()和notify()
问题:有时会出现,线程之间互相等待的问题。有没有好的解决方法?wait()?
结论:必须在同步的方法或区块中才能调用wait()方法。所以,要进行合理的线程调度,必须编写合理的调度逻辑,可以避免线程之间互相等待的问题(可以参考生产者-消费者模式)。
暂时不去改变801现有的线程逻辑。因为业务复杂,不方便再一个调度对象。加锁也会降低效率。
下面给出经典的,生产者-消费者模式:
Clerk.java:
package onlyfun.caterpillar;
public class Clerk {
// -1 表示目前没有产品
private int product = -1;
// 这个方法由生产者调用
public synchronized void setProduct(int product) {
if(this.product != -1) {
try {
// 目前店员没有空间收产品,请稍候!
wait();
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
this.product = product;
System.out.printf("生产者设定 (%d)%n", this.product);
// 通知等待区中的一个消费者可以继续工作了
notify();
}
// 这个方法由消费者调用
public synchronized int getProduct() {
if(this.product == -1) {
try {
// 缺货了,请稍候!
wait();
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
int p = this.product;
System.out.printf("消費者取走 (%d)%n", this.product);
this.product = -1; // 取走产品,-1表示目前店员手上无产品
// 通知等待区中的一个生产者可以继续工作了
notify();
return p;
}
}
Producer.java:
package onlyfun.caterpillar;
public class Producer implements Runnable {
private Clerk clerk;
public Producer(Clerk clerk) {
this.clerk = clerk;
}
public void run() {
System.out.println("生产者开始生产整数......");
// 生产1到10的整数
for(int product = 1; product <= 10; product++) {
try {
// 暂停随机时间
Thread.sleep((int) Math.random() * 3000);
}
catch(InterruptedException e) {
e.printStackTrace();
}
// 将产品交给店员
clerk.setProduct(product);
}
}
}
Consumer.java:
package onlyfun.caterpillar;
public class Consumer implements Runnable {
private Clerk clerk;
public Consumer(Clerk clerk) {
this.clerk = clerk;
}
public void run() {
System.out.println("消费者开始消耗整数......");
// 消耗10个整数
for(int i = 1; i <= 10; i++) {
try {
// 等待随机时间
Thread.sleep((int) (Math.random() * 3000));
}
catch(InterruptedException e) {
e.printStackTrace();
}
// 从店员处取走整数
clerk.getProduct();
}
}
}