以前线程总是使用new Thread().start()这种方式,或者使用线程池ThreadPoolExecutor管理,但是线程池只能控制数量,无法控制逻辑,各种线程之间的逻辑关系和顺序等
所以我封装了一个线程管理的类TaskHelper
TaskHelper主要功能
1.很多线程集中管理起来使用单线程多任务模式简化逻辑,特别是网络线程
2.串行的执行方式,可以在不同的类里创建任务并且排队执行,非常方便的管理了线程,例如多同一个文件的io操作,简单的处理
3.不同id的线程可以通过join来管理顺序,简化了很多操作,优化项目结构
TaskHelper 实现代码
import android.os.Process;
import android.util.Log;
import android.util.SparseArray;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class TaskHelper {
private final static String TAG = "TaskHelper";
private SparseArray<SingleTask> helperArray;
private volatile static TaskHelper instance;
public static TaskHelper getInstance() {
if (instance == null) {
synchronized (TaskHelper.class) {
if (instance == null) {
instance = new TaskHelper();
}
}
}
return instance;
}
private TaskHelper() {
if (helperArray == null) {
helperArray = new SparseArray<SingleTask>();
}
}
public static SingleTask getTask(int taskId) {
TaskHelper helper = getInstance();
SingleTask task;
synchronized (helper.helperArray) {
task = helper.helperArray.get(taskId);
if (task == null) {
task = new SingleTask(taskId);
helper.helperArray.put(taskId, task);
}
}
return task;
}
public void cancel() {
synchronized (helperArray) {
int size = helperArray.size();
for (int i = 0; i < size; i++) {
SingleTask task = helperArray.valueAt(i);
task.cancel();
}
helperArray.clear();
}
instance = null;
}
public void cancel(int taskId) {
SingleTask task = null;
synchronized (helperArray) {
task = helperArray.get(taskId);
if (task != null) {
task.cancel();
helperArray.remove(taskId);
}
}
}
public static class SingleTask {
private BlockingQueue<Runnable> queue;
private boolean isRun = false;
private int taskId;
private final Object lock = new Object();
private Thread mThread;
private SingleTask(int taskId) {
this.taskId = taskId;
queue = new LinkedBlockingQueue<Runnable>();
}
public boolean contains(String runnableName) {
for (Runnable r : queue) {
if (r.getClass().getName().equals(runnableName)) {
return true;
}
}
return false;
}
public void addTaskAndRun(Runnable runnable) {
int size = queue.size();
queue.add(runnable);
start();
}
public SingleTask addTask(Runnable runnable) {
queue.add(runnable);
return this;
}
public void join() {
boolean b;
synchronized (lock) {
b = isRun;
}
if (b) {
try {
mThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void cancel() {
queue.clear();
}
public void start() {
synchronized (lock) {
if (isRun) {
return;
}
isRun = true;
mThread = new Thread() {
public void run() {
Runnable runnable;
try {
while (isRun
&& (runnable = queue.poll(200,
TimeUnit.MILLISECONDS)) != null) {
Log.i(TAG, "run task name:"
+ runnable.getClass().getName() + taskId);
try {
runnable.run();
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
isRun = false;
TaskHelper.getInstance().cancel(taskId);
}
};
mThread.setPriority(Process.THREAD_PRIORITY_BACKGROUND);
mThread.start();
}
}
}
}
可以创建一个taskId生成器,统一管理所有的taskId
public class TaskIdFactory {
private static int id = 0;
public static int gen() {
int newId;
synchronized (TaskIdFactory.class) {
if (id == Integer.MAX_VALUE - 1) {
id = 0;
}
++id;
newId = id;
}
return newId;
}
}
使用方法
1.运行线程
TaskHelper.getTask(TaskIdFactory.gen()).addTaskAndRun(new Runnable() {
@Override
public void run() {
//TODO
}
});
2.单线程模式
int taskId = TaskIdFactory.gen();
TaskHelper.getTask(taskId).addTaskAndRun(new Runnable() {
@Override
public void run() {
//任务1
}
});
TaskHelper.getTask(taskId).addTaskAndRun(new Runnable() {
@Override
public void run() {
//任务2
}
});
当任务1和任务2的taskId相同时,任务1和任务2就会按顺序排队运行
3.如果当你在某个地方运行了很多个串联线程,然后又退出了这个界面,就可以使用
TaskHelper.getTask(taskId).cancel();
停止该线程,使排在队列后面没有运行的任务释放掉,不会再运行了。
4.如果退出了应用,则可以直接关闭所有任务
TaskHelper.getInstance().cancel();
5.两个线程直接的顺序管理,例如你的下一个界面要显示的数据要依赖任务的结果,但是任务不是在这个页面启动的。
比如,我做一个应用商店的时候,首页要显示需要更新的应用数量,就需要在首页去请求更新应用数据,但是二级页面需要更新的应用数据也依赖这个结果。如果打开二级页面的时候这个结果还没返回,就可以使用TaskHelper的线程join,来完成这个功能。这里没必要去启动Service实现那么麻烦,直接在首页使用
TaskHelper.getTask(taskId1).addTaskAndRun(new Runnable() {
@Override
public void run() {
//请求数据并保存
}
});
然后二级页面启动一个新的任务去等待结果
TaskHelper.getTask(taskId2).addTaskAndRun(new Runnable() {
@Override
public void run() {
TaskHelper.getTask(taskId1).join();
//读取task1里获取的数据
}
});
网友评论