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(); 
        } 
    } 
 }

Android的线程浅析 补充

时间: 2024-08-01 22:08:48

Android的线程浅析 补充的相关文章

c# 线程浅析(代理 、Invoke、Lock)

前言:本来想根据自己的经验总结一下c#线程相关的知识点, 写之前看了一些其他人的博客,发现自己也就掌握了不到三分之一....希望通过这次的博客将自己的知识点补充一下,写出更直白的博客和初学者分享. 这是我参考的博客地址:http://www.cnblogs.com/miniwiki/archive/2010/06/18/1760540.html  . 这个是他参考的英文原著地址:http://www.albahari.com/threading/ 原博客介绍的可以说深入浅出,鞭辟入里.不过我想写

Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask等

方法一:(java习惯,在android不推荐使用) 刚刚开始接触android线程编程的时候,习惯好像java一样,试图用下面的代码解决问题 new Thread( new Runnable() { public void run() { myView.invalidate(); } }).start(); 可以实现功能,刷新UI界面.但是这样是不行的,因为它违背了单线程模型:Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行. 方法二:(Thread+Handler)

【转】Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask

方法一:(java习惯,在android不推荐使用) 刚刚开始接触android线程编程的时候,习惯好像java一样,试图用下面的代码解决问题 new Thread( new Runnable() {         public void run() {              myView.invalidate();         }            }).start(); 复制代码 可以实现功能,刷新UI界面.但是这样是不行的,因为它违背了单线程模型:Android UI操作并不

Android源码浅析(三)——Android AOSP 5.1.1源码的同步sync和编译make,搭建Samba服务器进行更便捷的烧录刷机

Android源码浅析(三)--Android AOSP 5.1.1源码的同步sync和编译make,搭建Samba服务器进行更便捷的烧录刷机 最近比较忙,而且又要维护自己的博客,视频和公众号,也就没仔细的梳理源码的入门逻辑,今天也就来讲一个源码的玩法,各位看官,一起学习学习! 看本篇博客之前,先看下我的前面两篇 Android源码浅析(一)--VMware Workstation Pro和Ubuntu Kylin 16.04 LTS安装配置 Android源码浅析(二)--Ubuntu Roo

Android源码浅析(一)——VMware Workstation Pro和Ubuntu Kylin 16.04 LTS安装配置

Android源码浅析(一)--VMware Workstation Pro和Ubuntu Kylin 16.04 LTS安装配置 最近地方工作,就是接触源码的东西了,所以好东西还是要分享,系列开了这么多,完结 的也没几个,主要还是自己覆盖的太广了,却又不精通,嘿嘿,工作需要,所以写下了本篇博客 一.VMware 12 我选择的虚拟机试VMware,挺好用的感觉,下载VMware就不说了,善用搜索键嘛,这里我提供一个我现在在用的 下载地址:链接:http://pan.baidu.com/s/1k

android 进程/线程管理(四)续----消息机制的思考(自定义消息机制)

继续分析handler 和looper 先看看handler的 public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } 所以消息的处理分层三种,就是 1.传入一

Android的线程和线程池

原文链接,转载请注明出处 http://sparkyuan.me/2016/03/25/Android的线程和线程池/ 在Java中默认情况下一个进程只有一个线程,也就是主线程,其他线程都是子线程,也叫工作线程.Android中的主线程主要处理和界面相关的事情,而子线程则往往用于执行耗时操作.线程的创建和销毁的开销较大,所以如果一个进程要频繁地创建和销毁线程的话,都会采用线程池的方式. Android中线程的形态 传统的Thread AsyncTask HandlerThread IntentS

Android技术11:Android的线程模型

1.Android的单线程模型 在android应用程序启动时,Android会同时启动一个对应的主线程Main Thread.主线程主要负责处理UI方面的事件,所以又称UI线程.Android应用程序必须遵守单线程模型原则:androidUI操作不是线程安全的,并且这些操作必须在UI线程中完成.UI线程负责事件监听和绘图处理,因此必须保证UI线程能够随便响应用户,所以那些非常耗时的,必须放到其他线程中处理,如网络连接,数据库读取等操作,否超过一定时间没有响应,则应用程序就会终止. 2.消息队列

Android UI线程和非UI线程

UI线程及Android的单线程模型原则 当应用启动,系统会创建一个主线程(main thread). 这个主线程负责向UI组件分发事件(包括绘制事件),也是在这个主线程里,你的应用和Android的UI组件(components from the Android UI toolkit (components from the android.widget and android.view packages))发生交互. 所以main thread也叫UI thread也即UI线程. 系统不会为