美文网首页
十八、ThreadLocal实战(模拟实现一个简单版本的Hand

十八、ThreadLocal实战(模拟实现一个简单版本的Hand

作者: 大虾啊啊啊 | 来源:发表于2021-06-12 17:40 被阅读0次

    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的线程中的消息队列,往里存入消息,即主线程中的消息队列。而在主线程中我们又开启了一个无线循环,从当前线程的消息队列取消息,因此达到了线程切换的效果。

    相关文章

      网友评论

          本文标题:十八、ThreadLocal实战(模拟实现一个简单版本的Hand

          本文链接:https://www.haomeiwen.com/subject/soaleltx.html