关闭

Android系统运行架构之--生产-消费者模型详解

标签: 架构设计
507人阅读 评论(3) 收藏 举报

一个系统是如何运行起来的?通过安卓的源码分析我们大概可以知道,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();


    }

}
1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:12128次
    • 积分:485
    • 等级:
    • 排名:千里之外
    • 原创:38篇
    • 转载:0篇
    • 译文:0篇
    • 评论:5条
    最新评论