我们知道CPU处理多线程时是利用线程调度来实现的,线程调度主要依据线程的组别(是否前台)和优先级来进行,我们可以利用一个线程来模拟CPU的单核行为,对多任务进行调度。
在任务执行过程中可能发生各种各样的状态和阶段,可以利用监听者模式,来通知监听者任务的调度状态。
-
(4)任务调度主线程:
首先定义一个监听器类,用于线程执行状态的反馈;
public class MyListener {
public void downloadAppStarted(){};
public void downloadAppFinished(){};
}
- 实现主控制器,首先该控制器必须为单例,其次其为一个线程,不断的循环处理任务,可执行任务封装为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();
}
/**
* 构造方法
* @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;
}