您的位置:首页 > 运维架构 > 网站架构

handler原理分析及模仿handler实现简单主/子线程通信架构

2017-06-12 00:39 936 查看

1、分析handler原理

主线程和子线程通信通常靠Handler,要实现通信,需要Handler、MessageQueue、Message、Looper

用图表示



每个Handler都有一个Looper对象,而Looper对象的生成过程是

//sThreadLocal.get() will return null unless you've called prepare()
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static void prepare(){
if(sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}


Looper对象是保存在ThreadLocal当中。

ThreadLocal用于线程间的数据隔离,保证数据安全。

给当前线程关联一个Looper对象。

sThreadLocal.set(new Looper());



在android程序的入口ActivityThread中,默认为主线程关联了一个Looer对象,所以在调用Handler时,我们不用自己给主线程关联Looper对象,也就是Looper.prepare()

ActivityThread.java

public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
Looper.loop()

}


Looper.java中

public static void prepareMainLooper() {
prepare();
...
}


2、模范Handler实现主/子线程通信

新建Handler.java

package com.handler;

/**
* Created by Tony on 2017/6/11.
*/

public class Handler {

private MessageQueue mQueue;

//Handler的初始化在主线程中完成
public Handler() {
//获取主线程的Looper对象
this.mQueue = Looper.myLooper().mQueue;
}

/**
* 发送消息,压入队列
* @param msg
*/
public void sendMessage(Message msg) {
msg.target = this;
mQueue.enqueueMessage(msg);
}

public void dispatchMessage(Message msg) {
handleMessage(msg);
}

public void handleMessage(Message msg) {
}
}


新建Looper文件

package com.handler;

/**
* Created by Tony on 2017/6/11.
*/

public final class Looper {

//每一个主线程都有一个Looper对象
//Looper对象保存在ThreadLocal,保证了线程数据的隔离
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

//一个Looper对象对应一个消息队列
MessageQueue mQueue;

private Looper() {
mQueue = new MessageQueue();
}

public static void prepare() {
if (sThreadLocal.get()!=null){
throw new RuntimeException("only one looper may be created per thread");
}
sThreadLocal.set(new Looper());
}

/**
* 获取当前线程的Looper对象
* @return
*/
public static Looper myLooper() {
return sThreadLocal.get();
}

/**
* 轮询消息队列
*/
public static void loop() {
Looper me = myLooper();
if (me == null) {
throw  new RuntimeException("");
}

MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next();
if (msg == null) {
continue;
}
//转发给Handler
msg.target.dispatchMessage(msg);

}
}

}


新建MessageQueue

package com.handler;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* Created by Tony on 2017/6/11.
*/

public class MessageQueue {

/**
* 消息队列应该要有大小限制
* 消息队列满了,子线程停止发送消息,阻塞
* 消息队列为空,主线程Looper停止轮循,阻塞
*/

//通过数组的结构存储Message对象
Message[] items ;

//入队与出队元素索引位置
int putIndex;
int takeIndex;
//计数器
int count;
//互斥锁
private Lock lock;
//条件变量
private Condition notEmpty;
private Condition notFull;

public MessageQueue() {
this.items = new Message[50];
this.lock = new ReentrantLock();
this.notEmpty = lock.newCondition();
this.notFull = lock.newCondition();

}

/**
* 入队列(子线程运行)
* @return
*/
public void enqueueMessage(Message msg) {
try {
lock.lock();
//消息队列满了,子线程挺好i发送消息,阻塞
while (count == items.length)
{
try {
notFull.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
items[putIndex] = msg;
//循环取值
putIndex = (++putIndex == items.length) ? 0:putIndex;
count++;
//有新的Message对象,通知主线程
notEmpty.signal();
} finally {
lock.unlock();
}
}

/**
* 出队列(主线程运行)
* @return
*/
public Message next() {

Message msg = null;
try {
//消息队列为空,主线程Looper停止轮询,阻塞
lock.lock();
while (count == 0) {
try {
notEmpty.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
msg = items[takeIndex];//取出
items[takeIndex] = null;//元素置空
takeIndex = (++takeIndex == items.length) ? 0 : takeIndex;
count--;

//使用了一个的Message对象,通知子线程,可以继续生产
notFull.signal();
} finally {
lock.unlock();
}


这里写代码片

新建Message.java

package com.handler;

/**

* Created by Tony on 2017/6/11.

*/

public class Message {
Handler target;

public int what;

public Object obj;

@Override

public String toString() {

return obj.toString();

}

}
return msg;

}
}


新建测试文件HandlerTest.java

package com.handler;

import java.util.UUID;

/**
* Created by Tony on 2017/6/12.
*/

public class HandlerTest {

public static void main(String[] args) {
//轮询器初始化
Looper.prepare();
//主线程
final Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
System.out.println(Thread.currentThread().getName() + ",received: "+msg.toString()
);
}
};

//子线程发送消息
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
Message msg = new Message();
msg.what = 1;
synchronized (UUID.class){
//加锁,线程安全
msg.obj = Thread.currentThread().getName() +",send message:"+ UUID.randomUUID().toString();
}
handler.sendMessage(msg);
System.out.println(msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}

}
}
}).start();
}
//开始轮询
Looper.loop();
}

}


测试结果如下:



以上用了较简单的方式实现了主线程和子线程的通信。

源码地址:

https://github.com/fsdsds/HandlerDemo
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  handler