1. 程式人生 > >手動實現多工排程控制器

手動實現多工排程控制器

我們知道CPU處理多執行緒時是利用執行緒排程來實現的,執行緒排程主要依據執行緒的組別(是否前臺)和優先順序來進行,我們可以利用一個執行緒來模擬CPU的單核行為,對多工進行排程。

在任務執行過程中可能發生各種各樣的狀態和階段,可以利用監聽者模式,來通知監聽者任務的排程狀態。

  1. 4)任務排程主執行緒:

    首先定義一個監聽器類,用於執行緒執行狀態的反饋;
public class MyListener {

	public void downloadAppStarted(){};
	
	public void downloadAppFinished(){};
	

}

  1. 實現主控制器,首先該控制器必須為單例,其次其為一個執行緒,不斷的迴圈處理任務,可執行任務封裝為
    Command,且其必須實現Comparable介面,用以對不同優先順序的任務進行排程。

1)任務封裝:

	/**
	 * 訊息佇列中的命令封裝
	 * 命令排程:1比較是否為isForeGround執行緒 2比較sequence 大小,越大優先順序越高 
	 * @author 
	 *
	 */
	static class Command implements Comparable<Command> {

		public Runnable runnable;
		public MyListener mListener;
		public String description;
		boolean isForeGround;		//是否為前臺程序
		
		int sequence ;
		@Override
		public int compareTo(Command another) {
			// TODO Auto-generated method stub
			if (another.isForeGround && !isForeGround) {
				return 1;
			} else if(!another.isForeGround && isForeGround) {
				return -1;
			} else {
				return sequence - another.sequence;
			}
		}
		
	}

2)主控制器類:

	public class MyController implements Runnable {
		private Thread mThread; //當前主執行緒類的執行執行緒
		private BlockingQueue<Command> mCommands = new PriorityBlockingQueue<MyController.Command>();
		private boolean mBusy = false; //標識當前執行緒的執行狀態;
		private static AtomicInteger sequencing = new AtomicInteger(0); //執行緒安全的整數,用來定義執行緒優先順序,
		//記錄監聽介面,口需要通知介面時,遍歷所有介面,進行通知
		private Set<MyListener> mListeners = new CopyOnWriteArraySet<MyListener>();
		private Application mApplication;
	
	
		private static MyController inst = null;
		
		/** 方法前加synchronized 與方法內部使用雙重檢查有什麼區別
		 * 單例工廠類方法
		 * @return
		 */
		public synchronized static MyController getInstance(Application application) {
			if(inst == null) {
				inst = new MyController(application);
			}
			return inst;
		}
		
		(3)構造方法為private ,且在構造方法中開啟自己的主執行緒
		/**
		 * 構造方法
		 * @param application
		 */
		private MyController(Application application) {
			mApplication = application;
			mThread = new Thread(this);//執行緒使用runnable物件初始化
			mThread.setName("MyController");
			mThread.start();
		}
(3)構造方法為private ,且在構造方法中開啟自己的主執行緒
		/**
		 * 構造方法
		 * @param application
		 */
		private MyController(Application application) {
			mApplication = application;
			mThread = new Thread(this);//執行緒使用runnable物件初始化
			mThread.setName("MyController");
			mThread.start();
		}

4)任務排程主執行緒:

		@Override
		public void run() {
			// TODO Auto-generated method stub
			Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
			while(true) {
				String commanDescription = null;
				try {
					final Command command = mCommands.take();
					
					if(command != null) {
						commanDescription = command.description;
						mBusy = true;
						
						//任務執行成功,訊息通知
						for (MyListener l : getListeners(command.mListener)) {
							l.downloadAppStarted();
						}
						try {
							command.runnable.run();
						} catch(Exception e){
							//如果執行過程中出錯,則重新過30s重新把任務放入佇列
							new Thread() {
	
								@Override
								public void run() {
									// TODO Auto-generated method stub
									try {
										sleep(30 * 1000);
										mCommands.put(command);
									} catch (InterruptedException e){
										e.printStackTrace();
									}
								}
								
							}.start();
						}
					}
					
					//任務執行成功,訊息通知
					for (MyListener l : getListeners(command.mListener)) {
						l.downloadAppFinished();
					}
				} catch(Exception e) {
	//				e.printStackTrace();
					Log.e("TAGD", "Error running command '" + commanDescription + "'", e);
				}
				mBusy = false;
			}
		}

5)任務新增

		/**
		 * 任務佇列任務管理,任務新增
		 * 每次新增任務,如果失敗,重複新增5次,如果仍然失敗可以丟擲錯誤
		 */
		private void putCommand(BlockingQueue<Command> queue, String description, MyListener listener, Runnable runnable, boolean isForeGround) {
			int retries = 5;
			Exception e = null;
			while(retries-- > 0) {
				try {
					Command command = new Command();
					command.mListener = listener;
					command.description = description;
					command.isForeGround = isForeGround;
					command.runnable = runnable;
					queue.put(command);
					return ;
				} catch (InterruptedException ie) {
					
					try {
						Thread.sleep(200);
					} catch (InterruptedException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
					e = ie;
				}
			}
			throw new Error(e);
		}
		
		/**
		 * 預設新增到後臺
		 * @param description
		 * @param listener
		 * @param runnable
		 */
		private void putBackground(String description, MyListener listener, Runnable runnable) {
			putCommand(mCommands, description, listener, runnable, false);
		}
		
		/**
		 * 預設新增到前臺組
		 * @param description
		 * @param listener
		 * @param runnable
		 */
		private void putForground(String description, MyListener listener, Runnable runnable) {
			putCommand(mCommands, description, listener, runnable, true);
		}

6)監聽器控制:
		/**
		 * 監聽通知
		 */
		public void addListener(MyListener listener) {
			mListeners.add(listener);
		}
		
		public void removeListener(MyListener listener) {
			mListeners.remove(listener);
		}
		
		public Set<MyListener> getListeners(MyListener listener) {
			if(listener == null) {
				return mListeners;
			}
			
			Set<MyListener> listeners = new HashSet<MyListener>(mListeners);
			listeners.add(listener);
			return listeners;
		}