Android的线程浅析 补充

一、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("生产者开始生产整数......"); 
 
        // 生产110的整数
        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(); 
        } 
    } 
 }

 

 

Android的线程浅析 补充,,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。