参考教程:http://www.sohu.com/a/237792762_659256

首先说一下这里面涉及到的线程:

1.mainLooper:

  这个线程可以理解为消费者线程,里面运行了一个死循环,不断进行消息出队和处理消息这两个动作。

2.workLooper:

  这个线程就相当于是生产者线程,进行消息入队。

3.程序本身的线程:

  这个线程是隐式的,也就是我们运行程序的这个线程,知道有这样一个东西的存在能帮助我们理解整个程序的运行。

然后介绍每一个类:

1.Message:

  这个类的作用是存储一个生产者生产出来的具体的消息,就类似链表队列中的一个节点,自行定义需要存储的内容。

  code:消息要执行的具体动作代码

  msg:消息内容

  target:用来关联hadler,根本目的时为了使这几个类共享一个MessageQueue,这个很重要

2.MessageQueue:

  这个类就是生产者和消费者线程需要共享的一个存储消息的队列,生产者将消息放入这个队列,消费者取出消息并处理。

  内部实现是用了BlockingQueue,这个队列特别的地方就是出队和入队的时候是阻塞的,也就是说当队列中没有元素的时候,出队这个动作会引起线程阻塞,直到有元素入队;同理入队也会因为队列满而引起线程阻塞,直到有元素出队。

  这个类中定义了两个方法:next和enqueueMessage分别对应出对和入队。  

  需要考虑的就是如何将生产者和消费者多线程共享这个队列?这个在下面解释。

3.Looper

  这个类是整个机制的核心,理解了这个类这个机制怎样运行的也就基本清楚了。

  这个类主要是为mainThread服务的,类中定义了一个静态常量ThreadLocal,用来保存某个线程的共享变量,在这里它存的是一个:Looper,也就是这个类本身的一个实例。

  mainThread这个线程需要在开始线程的时候通过Looper.prepareMainLooper()创建一个looper。然后调用loop(),这个函数就是mainThread的主循环,不断地做两件事:消息出队和处理消息。

4.Handler:

  这个类主要定义了两个方法:sendMessage()和handleMessage(),即发送消息和处理消息,其中sendMessage()就是将消息入队,而handleMessage()设计成抽象方法,根据不同的实际情况设计不同的消息处理方法。

介绍完这四个类之后,要思考的就是生产者和消费者对MessageQueue的共享问题

  主程序开启了mainThread进程,这个进程在一开始就创建了一个Looper和一个mq,由于一开始这个mq是一个空队列,mainThread执行到loop()里的for循环时被阻塞在msg = me.mq.next();此时的程序并不会因此停止,而是向下执行,创建了一个handler,hadler中传入了mainThread中创建的那个Looper,并将这个Looper中的mq和hadler中的mq相关联,换句话说,此时handler中的mq就是mainThread中looper的mq。程序接着往下走,又创建了一个workThread,这个线程传入message,这个message除了保存了自身的信息之外,还保存了刚刚创建的handler,把这样的message传入workThread执行入队操作时,就能够将这个message存入handler中的mq中,此时也就将生产者和消费者这两个线程的MessageQueue指向了同一片内存。

  为什么要把MainThread创建的looper保存在ThreadLocal中?为什么要设置成static final?

    这个东西叫做线程本地变量,也有些地方叫做线程本地存储,其实意思差不多。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。

    looper是在MainThread中创建的,也就是说每创建一个MainThead,这个MainThread中有就一个looper这样一个变量,不同的MainThread中有不同的looper。

    设置成static final 这样就保证Looper这个类在创建的时,ThreadLocal就已经声明和创建。

思考的还是不太全面,先把代码先贴在这里:

Message.java

package Handler_test;

public class Message {

    private int code;
private String msg;
Handler target; public Message() { } public Message(int code, String msg, Handler handler) {
this.code = code;
this.msg = msg;
this.target = handler;
} public int getCode() {
return code;
} public void setCode(int code) {
this.code = code;
} public String getMsg() {
return this.msg;
} public void setMsg(String msg) {
this.msg = msg;
} }

MessageQueue.java

package Handler_test;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; public class MessageQueue implements IMessageQueue{ private BlockingQueue<Message> queue; public MessageQueue(int cap) { this.queue = new LinkedBlockingQueue<>(cap);
} @Override
public Message next() throws InterruptedException {
// TODO Auto-generated method stub
return queue.take();
} @Override
public void enqueueMessage(Message msg) throws InterruptedException {
// TODO Auto-generated method stub
try {
queue.put(msg);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}

Handler.java

package Handler_test;

public abstract class Handler {

    private MessageQueue mq;

    public Handler(Looper looper) {
mq = looper.mq;
} public Handler() {
Looper.myLooper();
} public void sendMessage(Message msg) {
try {
mq.enqueueMessage(msg);
}catch(InterruptedException e){
e.printStackTrace();
}
} public abstract void handleMessage(Message msg); }

Looper.java

package Handler_test;

public class Looper {

    MessageQueue mq;

    //用来保存某个线程的共享变量
//为什么要做成常量?
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>(); private static Looper sMainLooper; public Looper() {
mq = new MessageQueue(2);
} public static void prepare() {
if(sThreadLocal.get() != null) {
throw new RuntimeException("一个线程只能创建一个looper");
}
sThreadLocal.set(new Looper());
} public static void prepareMainLooper() {
prepare();
//??直接写Looper行么
synchronized(Looper.class) {
if(sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
} public static Looper myLooper() {
// TODO Auto-generated method stub
return sThreadLocal.get();
} public static Looper getMainLooper() {
return sMainLooper;
} public static void Loop() {
final Looper me = myLooper();
if(me == null) {
throw new RuntimeException("No looper; Looper.prepared() wasn't called on this thread");
}
for(;;) {
Message msg = null;
try {
msg = me.mq.next();
}catch(InterruptedException e) {
e.printStackTrace();
}
if(msg != null) {
msg.target.handleMessage(msg);
}
}
}
}

Main.java

package Handler_test;

import java.util.Random;

public class Main {

    public static void main(String[] args) {

        MainThread mainThread = new MainThread();
//这里start()创建一个执行run()方法的新线程
//调用start方法表示此进程处于 可运行状态 ,但并不一定正在运行
//线程的调度依赖系统提供的服务
mainThread.start();
//mainThread在准备looper时耗时,而程序的读取不会因为线程的耗时而停止
//但是之后的程序需要mainThread创建好looper后才能执行
//我认为Thread.sleep(100);是表示这个程序的线程,
//而不是mainThread以及workThread中的任何一个
//当looper创建好后Looper.getMainLooper()判断非空,跳出循环,程序向下执行
//mainThread在创建完looper后由于mq中没有消息而卡在了msg = me.mq.next(); while(Looper.getMainLooper() == null) {
try {
Thread.sleep(100);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
//这里传入了mainThread中创建的looper
//handler的构造函数中:mq = looper.mq;也将looper中的mq传给了handler
//这样looper中的mq就和handler中的mq关联起来了
//也就是共用一片内存
Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
System.out.println("execute in: " +
Thread.currentThread().getName());
switch(msg.getCode()) {
case 0:
System.out.println("0 case");
break;
case 1:
System.out.println("1 case");
break;
case 2:
System.out.println("2 case");
break;
default:
System.out.println("default");
break;
}
}
}; //将前面写好的handler传入msg中
Message msg1 = new Message(0, "first", handler);
WorkThread workThread1 = new WorkThread(handler, msg1);
Message msg2 = new Message(2, "two", handler);
WorkThread workThread2 = new WorkThread(handler, msg2);
workThread1.start();
workThread2.start();
//workThread中的run方法执行入队操作handler.sendMessage(message);
//这时将msg放入了handler中定义的那个mq
//这个mq同时也是looper中的那个mq
//此时由于mq这个队列不为空,mainThread被唤醒
//继续执行msg.target.handleMessage(msg);
//由于loop()是一个死循环,mainThread在处理完一条msg之后会继续取下一条msg
//循环这个过程
} //为什么要把这两个线程做成内部类,放在外面不行么?
public static class WorkThread extends Thread{ private Handler handler; private Message message; public WorkThread(Handler handler, Message message) {
setName("Work Thread");
this.handler = handler;
this.message = message;
} @Override
public void run() {
//这句话可以不写么?
super.run();
//模拟耗时
Random random = new Random();
try {
Thread.sleep(random.nextInt(10)*30);
}catch(InterruptedException e) {
e.printStackTrace();
}
//消息入队
handler.sendMessage(message);
}
} public static class MainThread extends Thread{
public MainThread() {
setName("MainThread");
} @Override
public void run() {
super.run();
Looper.prepareMainLooper();
System.out.println(getName() + " the looper is prepared.");
Looper.Loop();
}
} }

最新文章

  1. 后缀数组(suffix array)详解
  2. 联合体(union)的使用方法及其本质
  3. 虚拟机和windows主机中的文件共享
  4. 整盘恢复黑苹果后,重新安装Win7,卡在正在启动
  5. 里面的div怎么撑开外面的div,让高度自适应
  6. Magic CSS3 – 创建各种神奇的交互动画效果
  7. CF 115B Lawnmower(贪心)
  8. 【转】AspNetPager分页控件用法
  9. gulp小记(无刷新重载样式)
  10. E/AndroidRuntime(1636): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.***.app.wx.MainActivity} : android.view.InflateException: Binary XML file line #51 :
  11. Ext通过后台校验字段是否重复
  12. 转HTMLTestRunner 生成测试报告
  13. Oracle EBS-SQL (INV-8):检查物料入库明细信息.sql
  14. 【基础】常用的机器学习&amp;数据挖掘知识点
  15. 微信商户/H5支付申请 被拒原因:网站存在不实内容或不安全信息
  16. ORA-01034: ORACLE not available问题
  17. python学习日记(内置函数补充)
  18. ASP.NET 性能监控工具和优化技巧
  19. jquery中找到元素在数组中位置,添加或者删除元素的新方法
  20. 解决win7 安装完jdk7后,再安装jdk8出现的问题 has value &#39;1.8&#39;, but &#39;1.7&#39; is required.

热门文章

  1. Emgu cv3.0.0 图像收集
  2. 项目一:第九天 1、前台客户登录 2、Jquery citypicker省市区三级联动插件 4、业务受理(在线下单)
  3. Redis了解
  4. Entity Framework Tutorial Basics(38):Explicit Loading
  5. Entity Framework Tutorial Basics(36):Eager Loading
  6. 数据结构_wow(泡泡的饭碗)
  7. mysql--表数据的操作
  8. Java50道经典习题-程序31 数组逆序
  9. 利用excel制作二维码
  10. 搭建 pytorch框架