1、創建Looper類
static class Lopper {
static final ThreadLocal<Lopper> threadLocal = new ThreadLocal<Lopper>();
private LinkedBlockingQueue<Message> msgQueue;
public LinkedBlockingQueue<Message> getMsgQueue() {
return msgQueue;
}
public Lopper() {
msgQueue = new LinkedBlockingQueue<Message>();
}
public static void prepare() {
if (threadLocal.get() == null) {
threadLocal.set(new Lopper());
}
}
public static Lopper myLooper() {
return threadLocal.get();
}
public static void loop() {
while (true) {
LinkedBlockingQueue<Message> queue = Lopper.myLooper().getMsgQueue();
if (queue != null && queue.size() > 0)
{
try {
Message message = queue.take();
message.target.handleMessage(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
2、創建Handler類
static class Handler {
private Lopper lopper;
/**
* 在哪個線程創建Handler,
* 就是拿哪個線程的Loopper
*/
public Handler() {
lopper = Lopper.myLooper();
}
public void handleMessage(Message message) {
}
public void sendMessage(Message message) {
message.target = this;
try {
lopper.getMsgQueue().put(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3、創建Message類
static class Message {
public Handler target;
public Object content;
}
4、測試
public static void main(String[] args) {
final Lopper lopper = new Lopper();
lopper.prepare();
final Handler handler = new Handler(){
@Override
public void handleMessage(Message message) {
super.handleMessage(message);
System.out.println("調用後的線程:" + Thread.currentThread().getName());
System.out.println("接受消息:"+message.content);
}
};
new Thread() {
@Override
public void run() {
System.out.println("調用前的線程:" + Thread.currentThread().getName());
Message message = new Message();
message.content = "hello world";
handler.sendMessage(message);
System.out.println("發送消息:"+message.content);
}
}.start();
try {
Thread.sleep(200);
lopper.loop();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
調用前的線程:Thread-0
發送消息:hello world
調用後的線程:main
接受消息:hello world
- 簡單版和Android中的版本使用有一點區別是,在安卓版本中主線程一開始就調用了 looper.loop(),使當前線程進入無線循環輪詢消息,因爲在安卓中一旦沒有消息的時候,便阻塞在loop中的queue.next()中的nativePollOnce方法裏,會使得當前線程休眠,釋放CPU資源,直到下個消息到達,通過往pipe管道端寫入數據來喚醒線程工作,這樣就不會因爲主線程無線循環導致阻塞。
- 而我們這裏演示爲了不使得主線程阻塞,我們先是往消息隊列裏存數據,然後再去循環拿消息進行處理,最終目的都是達到了線程切換的效果。
- Handler線程切換的主要核心是靠ThreadLocal來實現,ThreadLocal使得每個線程擁有自己的一份副本,從而達到數據隔離。因爲我們的Handler是由主線程創建,因此我們在發消息往消息隊列裏存消息的時候,是通過拿到創建Handler的線程中的消息隊列,往裏存入消息,即主線程中的消息隊列。而在主線程中我們又開啓了一個無線循環,從當前線程的消息隊列取消息,因此達到了線程切換的效果。