1. 程式人生 > >Android系統執行架構之--生產-消費者模型詳解

Android系統執行架構之--生產-消費者模型詳解

一個系統是如何執行起來的?通過安卓的原始碼分析我們大概可以知道,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系統執行架構--生產-消費者模型

一個系統是如何執行起來的?通過安卓的原始碼分析我們大概可以知道,Android在驅動層,在上層都採取生產-消費者模型來構建整個系統;因此對於生產-消費者模型的理解,就顯得十分重要;首先通過下圖,讓大家對生產-消費者模型有一個初步認識: 生產者負責向佇

C++11 併發指南九(綜合運用: C++11 多執行緒下生產者消費者模型)

前面八章介紹了 C++11 併發程式設計的基礎(抱歉哈,第五章-第八章還在草稿中),本文將綜合運用 C++11 中的新的基礎設施(主要是多執行緒、鎖、條件變數)來闡述一個經典問題——生產者消費者模型,並給出完整的解決方案。 生產者消費者問題是多執行緒併發中一個非常經典的問題,相信學過作業系統課程的同學都清楚

C++11 多執行緒下生產者消費者模型

 前面八章介紹了 C++11 併發程式設計的基礎(抱歉哈,第五章-第八章還在草稿中),本文將綜合運用 C++11 中的新的基礎設施(主要是多執行緒、鎖、條件變數)來闡述一個經典問題——生產者消費者模型,並給出完整的解決方案。 生產者消費者問題是多執行緒併發中一個非常

綜合運用: C++11 多線程下生產者消費者模型(轉)

並發 rep 生產 我會 交流 模型 操作 const ref 生產者消費者問題是多線程並發中一個非常經典的問題,相信學過操作系統課程的同學都清楚這個問題的根源。本文將就四種情況分析並介紹生產者和消費者問題,它們分別是:單生產者-單消費者模型,單生產者-多消費者模型,多生產

網絡通信協議三TCP/IP模型

udp protocol bubuko 傳遞 alt 公司 技術 png 代名詞 TCP/IP模型 註:PDU:Protocol Date Unit:表示對等層之間傳遞的數據單位 TCP:Transmission Control Protocol:傳輸控制協議 UD

Android中Canvas繪圖Shader使用圖文

概述 我們在用Android中的Canvas繪製各種圖形時,可以通過Paint.setShader(shader)方法為畫筆Paint設定shader,這樣就可以繪製出多彩的圖形。那麼Shader是什麼呢?做過GPU繪圖的同學應該都知道這個詞彙,Shader就

Android基礎————UI佈局UI美化分解

UI美化 (1)color資源: 1、values的color常量: 引用方式:@color/xxx 1. 設定字型的顏色 android:textColor="@color/white" 2. 設定佈局的背景顏色 android:background

Java多執行fork/join框架

這個框架的目的主要是更好地利用底層平臺上的多核CPU和多處理器來進行處理,解決問題時通常使用分治演算法或map/reduce演算法來進行.這個框架的名稱來源於使用時的兩個基本操作fork和join,可以類比於map/reduce中的map和reduce操作.fork操作的作

9 異常處理 操作系統 進程線程 隊列+生產消費者模型 進程同步 回調函數

共享數據 word import 可選 想要 線程組 show 內存 強制 異常處理 異常就是程序運行時發生錯誤的信號,在python中,錯誤觸發的異常如下 異常的種類: AttributeError 試圖訪問一個對象沒有的樹形,比如foo.x,但是foo

Java 多線程系列2——多線程的生命周期及生產消費者模型

wait 重要 strong clas 經典 關於 running 結束 準備 一、線程的生命周期及五種基本狀態 關於Java中線程的生命周期,首先看一下下面這張較為經典的圖: 上圖中基本上囊括了Java中多線程各重要知識點。掌握了上圖中的各知識點,Java中的多

java並發生產者消費者模型

isf tof on() acc sum sca span empty poll 生產者和消費者模型是操作系統中經典的同步問題。該問題最早由Dijkstra提出,用以

線程通信生產者消費者模型

釋放 另一個 gpo 停止 product @override getname -s rup   線程通信,是指線程之間的消息傳遞。   多個線程在操作同一個資源時,它們對共享資源的操作動作可能不同;它們共享同一個資源,互為條件,相互依賴,相互通信,從而讓任務向前推進。  

操作系統OS,Python - 生產者消費者模型

UC lease 整體 left 多個 eas 資源 解決 臨界區 1. 緩沖區(此處用阻塞隊列充當),解決消費者和生產者強耦合問題。(生產者和消費者不直接通信) 2. 通過平衡生產者線程和消費者線程,來提高程序整體處理數據速度。 3. 在並發編程中該模式能解決大多數並發問

Android系統原始碼分析-ContentProvider

距離上一次寫部落格已經半年多了,這半年發生了很多事情,也有了很多感觸,最主要是改變了忙碌了工作,更加重視身體的健康,為此也把工作地點從深圳這個一線城市換到了珠海,工作相對沒有那麼累,身體感覺也好了很多。所以在工作完成之餘,也有了更多的時間來自我學習和提高,後續會用更多時間來寫更多實用的東西,幫助我們理解

設計模式-生產消費者

看到這裡需先注意,消費量應大於生產量避免OOM package com.desigin.producerConsumer;import java.util.concurrent.BlockingQueue; public class Consumer implements Runnabl

【安卓本卓】Android系統原始碼篇(二)Source Insight

Source Insight(以下簡稱SI) 一、SI簡介        SI是一款面向專案開發的程式編輯器和程式碼瀏覽器,它提供了一個檢視將分散在各個地方的程式碼匯合在一起形成一個虛擬的整體,供開發者方便地閱讀和編輯,如下圖所示。它已經持續維護了10多年了,旨在提

Android系統功耗優化CPU

現在的處理器都支援DVFS - 動態頻率電壓調整,我們都知道DVFS的設計是為了low power,那麼CPU頻率和功耗之間的關係如何,執行在相同頻率處理A任務和B任務功耗就一樣嗎? 同任務不同頻率 在某Android平臺,在單執行緒執行dhrystone的情況

Android執行HandlerThread 完全

  之前對執行緒也寫過幾篇文章,不過倒是沒有針對android,因為java與android線上程方面大部分還是相同,不過本篇我們要介紹的是android的專屬類HandlerThread,因為HandlerThread在設定思想上還是挺值得我們學習的,那麼我們下面來

生產消費者模型程式碼示例

import time import random from multiprocessing import Process,Queue def producer(q,name,food): for i in range(4): time.sleep(random.

Android學習筆記——Android系統整體架構與原始碼目錄

首先要感謝**@劉望舒**大神的部落格,讓我們這些渣渣有途徑更快速地接觸到Android系統層的內容。 本篇部落格主要介紹了Android系統的整體架構及原始碼的目錄結構。 Android系統架構 Android的系統架構可以分為五層,分別是 應用層、應用框架