十八、ThreadLocal實戰(模擬實現一個簡單版本的Handler)

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的線程中的消息隊列,往裏存入消息,即主線程中的消息隊列。而在主線程中我們又開啓了一個無線循環,從當前線程的消息隊列取消息,因此達到了線程切換的效果。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章