java——利用生产者消费者模式思想实现简易版handler机制
参考教程: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(); } } }