十八、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的线程中的消息队列,往里存入消息,即主线程中的消息队列。而在主线程中我们又开启了一个无线循环,从当前线程的消息队列取消息,因此达到了线程切换的效果。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章