手動實現多工排程控制器
阿新 • • 發佈:2019-01-30
我們知道CPU處理多執行緒時是利用執行緒排程來實現的,執行緒排程主要依據執行緒的組別(是否前臺)和優先順序來進行,我們可以利用一個執行緒來模擬CPU的單核行為,對多工進行排程。
在任務執行過程中可能發生各種各樣的狀態和階段,可以利用監聽者模式,來通知監聽者任務的排程狀態。
-
(4)任務排程主執行緒:
首先定義一個監聽器類,用於執行緒執行狀態的反饋;
public class MyListener {
public void downloadAppStarted(){};
public void downloadAppFinished(){};
}
- 實現主控制器,首先該控制器必須為單例,其次其為一個執行緒,不斷的迴圈處理任務,可執行任務封裝為
(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)主控制器類:
(3)構造方法為private ,且在構造方法中開啟自己的主執行緒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(); }
/**
* 構造方法
* @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;
}