Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android的線程淺析 補充

Android的線程淺析 補充

編輯:關於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("生產者開始生產整數......"); 
 
        // 生產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(); 
        } 
    } 
 }

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved