十八、ThreadLocal实战(模拟实现一个简单版本的Hand
2021-06-12 本文已影响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的线程中的消息队列,往里存入消息,即主线程中的消息队列。而在主线程中我们又开启了一个无线循环,从当前线程的消息队列取消息,因此达到了线程切换的效果。