一个系统是如何运行起来的?通过安卓的源码分析我们大概可以知道,Android在驱动层,在上层都采取生产-消费者模型来构建整个系统;因此对于生产-消费者模型的理解,就显得十分重要;首先通过下图,让大家对生产-消费者模型有一个初步认识:
生产者负责向队列提交任务,消费者从队列取出任务,然后进行消费;
有人问,为什么要设计个这么个模型来用在软件开发中;因为这个模型很简单,很方便的将一个任务分解开来,有利于多线程的并发;有利于适应现代多核处理器,有利于现代操作系统通过分配时间片的方式来进行任务的运行;
生产-消费者模型的运用,有利于计算机更高效,更安全的管理利用唯一的硬件资源;
下面讲解生产-消费者模型的实现要点:
(一)设计队列
(二)设计提交任务的机制
(三)设计消费者消费模式
队列的设计相对简单,利用数据结构的知识就可以完成。
首先是队列元素:
/**
*
* @author 徐晔
* @note 队列元素
*/
public class Message {
public Runnable runnable;
public Message next;
public LooperHandler mHandler;
public int id;
public boolean flag = false;
public void recycle() {
mHandler = null;
next = null;
runnable = null;
}
}
然后是队列压入,取出接口类:
public class MessageQueue {
public Message start = null, end = null;
private boolean waitflag = false;
/** 构造队列 */
public MessageQueue() {
// 初始化一个链表
start = new Message();
end = new Message();
start.next = end;
end.next = start;
}
/**
* 判断队列是否为空
*/
public boolean isempty() {
// 当头尾相遇时,队列为空
if (start.next == end) {
return true;
} else {
return false;
}
}
/** 给队列插入任务
** 该方法是由生产者线程执行,因此需要在调用该方法的时候对队列进行一个锁操作
*/
public void postMessage(Message msg) {
System.out.println("插入任务");
// 尾插法
end.next.next = msg;
msg.next = end;
// 尾结点指向链表的最后一个元素
end.next = msg;
if (waitflag) {
synchronized (this) {
System.out.println("唤醒");
//由于该对象在一个线程中执行,因此也就只有这么一个线程在等待,因此调用的是notify();
notify();
}
}
}
/**
* 移除执行的元素
*/
private void remove(Message msg) {
start.next = msg.next;
if (start.next == end) {
end.next = start;
}
}
/**
* 获取元素
*
* @return
*/
public Message next() {
if (isempty()) {
synchronized (this) {
try {
waitflag = true;
System.out.println("进入等待");
//唤醒等待的线程
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("/**************************************************************/");
System.out.println("获取下一个消息");
waitflag = false;
Message msg = start.next;
remove(msg);
return msg;
}
}
第一个问题解决了,我们来看第二个问题:提交任务的机制?提交任务属于生产者线程给消费者线程提交任务,因此我们需要获取到消费者线程的任务队列的提交任务的接口;
下面是我的实现:
public class Looper {
/** 线程自带的队列 */
private MessageQueue queue = null;
/** 利用ThreadLocal来建立Thread和Looper的一一对应关系 */
private static ThreadLocal<Looper> loopdata = new ThreadLocal<Looper>();
private Looper() {
}
private void setQueue(MessageQueue queue) {
this.queue = queue;
}
/** 初始化该线程的队列 */
public final static void prepare() {
// 保证一个线程对应一个Looper,一个Looper包含一个MessageQueue
if (loopdata.get() == null) {
System.err.println("设置队列");
Looper l = new Looper();
//引出MessageQueue
l.setQueue(new MessageQueue());
loopdata.set(l);
}
}
//获取到和调用者线程对应的队列
public final static Looper get() {
return loopdata.get();
}
/** 给消费者线程的队列压入数据 */
void sendMessage(Message msg) {
//队列加锁很重要
synchronized (queue) {
queue.postMessage(msg);
}
}
/** 开始处理消息 */
public final static void Loop() {
Looper loop = loopdata.get();
MessageQueue mqueue = loop.queue;
// 进入死循环,处理消息
for (;;) {
Message msg = mqueue.next();
if (msg.mHandler == null) {
msg.mHandler = new LooperHandler(loop);
}
msg.mHandler.HandlerMessage(msg);
msg.recycle();
}
}
}
队列压入接口和消费接口
public class LooperHandler {
private Looper mLooper;
public LooperHandler(Looper looper) {
this.mLooper = looper;
}
/** 处理消息 */
void HandlerMessage(Message msg) {
Runnable r=msg.runnable;
if(r!=null){
r.run();
}
}
/** 将消息压入队列 */
public void sendMessage(Message msg) {
mLooper.sendMessage(msg);
}
}
好了,通过以上的构建,我们大概构造了生产–消费者模型:测试代码如下:
//生产者a
public class Producer implements Runnable {
private LooperHandler handler;
private int number = 0;
public Producer(LooperHandler handler) {
this.handler = handler;
}
@Override
public void run() {
while (true) {
number++;
final Message msg = new Message();
msg.mHandler = handler;
msg.id=number;
msg.runnable = new Runnable() {
@Override
public void run() {
System.out.println("Producer执行了第" + msg.id + "个任务");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
};
handler.sendMessage(msg);
System.out.println("提交了" + number + "次");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//生产者b
public class Producerb implements Runnable {
private LooperHandler handler;
private int number = 0;
public Producerb(LooperHandler handler) {
this.handler = handler;
}
@Override
public void run() {
while (true) {
number++;
final Message msg = new Message();
msg.mHandler = handler;
msg.id=number;
msg.runnable = new Runnable() {
@Override
public void run() {
System.out.println("Producerb执行了第" + msg.id + "个任务");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
};
handler.sendMessage(msg);
System.out.println("提交了" + number + "次");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
测试:
public class Customer {
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
Looper.prepare();
new Thread(new Producer(new LooperHandler(Looper.get()))).start();
new Thread(new Producer(new LooperHandler(Looper.get()))).start();
Looper.Loop();
super.run();
}
}.start();
new Thread() {
@Override
public void run() {
Looper.prepare();
new Thread(new Producerb(new LooperHandler(Looper.get()))).start();
Looper.Loop();
super.run();
}
}.start();
}
}
本文深入解析了生产-消费者模型在构建Android系统中的作用,通过队列设计、任务提交机制和消费者消费模式的实现,阐述了如何通过这种模型提高系统的效率和安全性。文中还详细介绍了模型的实现要点,包括队列元素设计、队列压入和取出接口,以及如何在生产者和消费者线程间传递任务。最后,通过测试代码验证了模型的有效性。
1377

被折叠的 条评论
为什么被折叠?



