synchronized简版Looper
2019-09-25 本文已影响0人
陆元伟
我们知道Looper的工作机制就是不断的从MessageQueue里面获取消息,没有消息的时候则等待,直到有消息到来,看Looper的源码发现阻塞等待和通知用的是linux的epoll,它是linux内核下高效的的异步唤醒机制。既然是等待和唤醒,那是不是只用java就可以处理了。于是利用synchronized实现一个简版的Looper
Message,里面只是简单的一个数据,并且简单用string类型
public class Message {
public Handler target;
public Message next;
public String data;
public Message(String data) {
this.data = data;
}
@Override
public String toString() {
return "data:"+data;
}
}
然后是Handler,也只是发送和处理两个简单方法
public class Handler {
Looper looper;
public Handler(Looper looper) {
this.looper = looper;
}
public void handlerMsg(Message msg) {
System.out.println("[handlerMsg]"+Thread.currentThread().getName()+","+msg);
}
public void sendMsg(Message msg) {
System.out.println("[sendMsg]"+Thread.currentThread().getName()+","+msg);
msg.target = this;
looper.mQueue.enqueueMessage(msg);
}
}
然后是MessageQueue,一个enqueueMessage方法,存储message,一个next方法,获取message,一个quit方法,结束等待。
public class MessageQueue {
public Message mMessages;
private boolean mQuitting;
public Message nextMsg() {
synchronized (this) {
for(;;) {
Message p = mMessages;
if(p==null) {
try {
System.out.println("wait....");
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(mQuitting) {
return null;
}
p=mMessages;
mMessages=mMessages.next;
return p;
}
}
}
void quit() {
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
notifyAll();
}
}
public int size() {
int size=0;
Message p = mMessages;
while(p!=null) {
size++;
p=p.next;
};
return size;
}
public void enqueueMessage(Message msg) {
synchronized (this) {
if(mMessages==null) {
mMessages = msg;
}else {
Message pre= mMessages;
Message p = pre.next;
while(p!=null) {
pre=p;
p=p.next;
};
pre.next = msg;
}
notifyAll();
}
}
}
Looper就简单了,从MessageQueue里面不断的获取消息,处理消息。
public class Looper {
MessageQueue mQueue=new MessageQueue();
private static Looper sMainLooper;
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public void loop() {
for(;;) {
Message msg=mQueue.nextMsg();
if(msg==null) {
return;
}
msg.target.handlerMsg(msg);
}
}
public void quit() {
mQueue.quit();
}
public static void prepareMainLooper() {
prepare();
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
private static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
public static Looper myLooper() {
return sThreadLocal.get();
}
}
public class LooperTest {
static Handler handler;
public static void main(String[] args) throws Exception {
//模拟主线程
Thread mainThread=new Thread(new Runnable() {
@Override
public void run() {
Looper.prepareMainLooper();
handler=new Handler(Looper.getMainLooper());
Looper.getMainLooper().loop();
System.out.println("quit");
}
});
mainThread.setName("mainThead");
mainThread.start();
//延迟是等主线程的loop()执行
Thread.sleep(100);
//模拟其他线程,发送消息
Thread t=new Thread() {
@Override
public void run() {
// TODO Auto-generated method stub
handler.sendMsg(new Message("1"));
handler.sendMsg(new Message("2"));
handler.sendMsg(new Message("3"));
}
};
t.setName("otherThread1");
t.start();
//模拟其他线程,发送消息
Thread t2=new Thread() {
@Override
public void run() {
// TODO Auto-generated method stub
handler.sendMsg(new Message("4"));
handler.sendMsg(new Message("5"));
handler.sendMsg(new Message("6"));
}
};
t2.setName("otherThread2");
t2.start();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//调用退出
Looper.getMainLooper().quit();
}
}).start();
}
}
打印的日志如下。
wait....
[sendMsg]otherThread1,data:1
[sendMsg]otherThread1,data:2
[sendMsg]otherThread1,data:3
[sendMsg]otherThread2,data:4
[sendMsg]otherThread2,data:5
[sendMsg]otherThread2,data:6
[handlerMsg]mainThead,data:1
[handlerMsg]mainThead,data:2
[handlerMsg]mainThead,data:3
[handlerMsg]mainThead,data:4
[handlerMsg]mainThead,data:5
[handlerMsg]mainThead,data:6
wait....
quit
当然我们这个是简单再简单不过的版本,只有发送和处理,消息也没有按照时间排序。但是处理整个流程和系统Looper大致相似。