生产者:往队列添加消息,当队列满的时候,不能再添加消息了,此时block(即消息阻塞了),当生产一个消息的时候,通知消费者有消息可以消费了。
消费者:从队列消费消息(获取),如果队列为空,则block,当消费者消费了一个消息的时候,通知生产者可以再生产消息。
好了废话不多说 直接上代码 代码中有注释
//Message类
/*
* 需要发送的handler
*/
public class Message {
/**
* 需要发送的Handler
*/
public com.kj.handlerlib.Handler target;
public String what;
public Message(String what) {
this.what = what;
}
@Override
public String toString() {
return "what: " + what;
}
}
//消息队列MessageqQ
public class MessageQueue {
//消息队列
private static final int count = 50;
/**
* 使用阻塞队列BlockingQueue解决生产者消费者
* 主要作用是效仿android源码native层的唤醒和堵塞消息队列的问题
* android源码使用的native方法nativePollOnce(阻塞),nativeWake(唤醒),这里使用另一种java并发提供的阻塞队列类替换
*/
private final BlockingQueue<Message> mMessageQueue;
public MessageQueue() {
mMessageQueue = new ArrayBlockingQueue<>(count);
}
public void enqueueMessage(Message msg) {
try {
mMessageQueue.put(msg);
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* 获取下一个消息对象
* 有消息对象时读取
*/
public Message next() {
try {
return mMessageQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
//消息循环looper类
/*
* 消息循环类
*/
public class Lopper {
/**
* 消息队列
*/
public MessageQueue mQueue;
/**
* ThreadLocal类用来提供线程内部的局部变量。
* 这种变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量
* 提供线程内部的局部变量,在本线程内随时随地可取,隔离其他线程
* <p>
* ThreadLocal解决多线程的并发问题
* 每个线程维护一个 ThreadLocalMap 的映射表,
* 映射表的 key 是 ThreadLocal 实例本身,value 是要存储的副本变量。
* ThreadLocal 实例本身并不存储值,它只是提供一个在当前线程中找到副本值的 key
* <p>
* 每个Thread维护一个ThreadLocalMap映射表,这个映射表的key是ThreadLocal实例本身,
* value是真正需要存储的Object
*/
private static final ThreadLocal<Lopper> sThreadLocal = new ThreadLocal<>();
private Lopper() {
mQueue = new MessageQueue();
}
/**
* Lopper 初始化
*
* @author LuoHao
* Created on 2018/2/25 14:04
*/
public static void prepare() {
if (sThreadLocal.get() != null) {
sThreadLocal.remove();
throw new RuntimeException("Only one Looper may be created per Thread");
}
sThreadLocal.set(new Lopper());
}
public static Lopper myLooper() {
return sThreadLocal.get();
}
/**
* 提供系统动力,让消息队列开始循环工作
*/
public static void loop() {
final Lopper me = myLooper();
if (me == null) {
sThreadLocal.remove();
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this Thread");
}
final MessageQueue queue = me.mQueue;
// 死循环开始遍历消息并分发
for (; ; ) {
// might block
Message msg = queue.next();
if (msg == null) {
// No message indicates that the message queue is quitting.
System.out.println(" No message indicates that the message queue is quitting.");
return;
}
msg.target.dispatchMessage(msg);
}
}
}
//Handler类
public class Handler {
/**
* 消息队列
*/
private final MessageQueue mQueue;
/**
* 消息循环
*/
private final Lopper mLooper;
public Handler() {
this(Lopper.myLooper());
}
public Handler(Lopper looper) {
mLooper = looper;
// 保证MessageQueue与Looper对应性
mQueue = mLooper.mQueue;
}
/**
* 发送消息
*
* @param msg message
* @author LuoHao
* Created on 2018/2/26 16:40
*/
public final void sendMessage(Message msg) {
// target是Handler本身
// 多线程中保证Handler的一致性,并且这句是在主线程中调用的,
// 当其调用自身的handleMessage()时才会有线程切换的效果
msg.target = this;
// enqueue a message
mQueue.enqueueMessage(msg);
}
/**
* 复写该方法 处理消息
*
* @author LuoHao
* Created on 2018/2/26 16:44
*/
public void handleMessage(Message msg) {
}
/**
* 面向对象设计模式
* 责任链调度原则
*
* @param msg message
*/
public void dispatchMessage(Message msg) {
handleMessage(msg);
}
}
//最后再来一个handler测试类
public class HandlerTest {
/**
* 线程数量
*/
private static final int THREAD_COUNT = 10;
private static ThreadFactory namedThreadFactory = new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "common-thread-pool");
}
};
/**
* Common Thread Pool
* <p>
* 手动创建线程池 建议不直接使用Executors.newCachedThreadPool()
*/
private static ExecutorService commonThreadPool = new ThreadPoolExecutor(5, 200,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1024),
namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
private static ThreadFactory namedThreadFactory2 = new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "single-thread-pool");
}
};
/**
* Single Thread Pool
* <p>
* 手动创建线程池代替直接显示new Thread的问题
*/
private static ExecutorService singleThreadPool = new ThreadPoolExecutor(1, 1
, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1024)
, namedThreadFactory2, new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) {
// 手写android 底层Handler机制实现框架
Lopper.prepare();
final Handler myHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
System.out.println("handle msg: thread:" + Thread.currentThread().getId() +
" Msg: " + msg.toString());
}
};
// 开启多线程
singleThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println("singleThreadPool function thread name: " +
Thread.currentThread().getName());
for (int i = 0; i < THREAD_COUNT; i++) {
commonThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println("commonThreadPool function thread name: " +
Thread.currentThread().getName());
Message msg = new Message(UUID.randomUUID().toString());
System.out.println("send Msg: thread: " + Thread.currentThread().getId() +
" Msg: " + msg.toString());
myHandler.sendMessage(msg);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
// new Thread().start()
Lopper.loop();
// 异常
throw new RuntimeException("Main thread loop unexpectedly exited");
}
}