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大致相似。

上一篇下一篇

猜你喜欢

热点阅读