synchronized簡版Looper

我們知道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大致相似。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章