多线程处理

package com.fcar.frameworks.tasks;


/**
 * 用于处理通讯收发的线程类。(这个注释似乎已经不能很好的描述其实际用途了,大概“执行一般性一次性后台任务的线程类更贴切”)<br/>
 * 同一时间一次只有一个对象可以运行
 */
public class CommThread extends Thread {
   /** 额外参数 */
   private Object mParam;
   /** 要执行的任务 */
   private ITask mTask;

   /**
    * 实现临界区的信号量
    */
   private static int times = 0;

   /**
    * 构造函数
    * @param t 任务
    * @param param 额外参数
    */
   public CommThread(ITask t, Object param) {
      mParam = param;
      mTask = t;
      super.start();
   }

   /**
    * 什么都不做,因为在构造器中已经启动线程,这里覆盖父类方法只是为了防止创建对象后又调用一次start方法
    */
   @Override
   public void start() {
   }

   /**
    * 用于同步访问times变量
    */
   private static final Object lock = new Object();

   /**
    * 进入临界区,一次只允许一个CommThread或者{@link TaskManager#addLoopTask_(int, ITask, Object) 循环任务压栈任务}进入临界区
    */
   public static void enterCriticalArea() {
      while (true) {
         synchronized (lock) {
            if (times == 0) {
               times = 1;
               break;
            }
         }
         TaskManager.Sleep(10);
      }
   }

   /**
    * 退出临界区,只有退出临界区以后别的CommThread或者{@link TaskManager#addLoopTask_(int, ITask, Object) 循环任务压栈任务}才可以进入临界区。
    * 如果你有程序进入临界区,一定要保证它一定会退出临界区
    */
   public static void exitCriticalArea()  {
      synchronized (lock) {
         times = 0;
      }
   }

   @Override
   public void run() {
      if (mTask == null)
         return;
      enterCriticalArea();
      // 写成try语句保证退出临界区执行
      try {
         TaskManager.loopTaskPause();
         mTask.doWork(mParam);
         TaskManager.loopTaskResume();
      } finally {
         exitCriticalArea();
      }
   }

}

package com.fcar.frameworks.tasks;

/**
 * 任务接口, 任何需要进行的工作都可以认为是一个Task
 */
public interface ITask {
   boolean doWork(Object param);
}

package com.fcar.frameworks.tasks;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

/**
 * 多重循环的任务, 多个循环任务同时循环
 */
public class MutiTasks implements ITask {

   /**
    * 任务列表
    */
   List<TaskObj> taskList;

   /**
    * 多重任务中每个任务的详细信息
    */
   public class TaskObj {
      /**
       * 任务过程
       */
      ITask task;
      /**
       * 额外参数
       */
      Object param;
      /**
       * 循环时间间隔
       */
      int loopTimes;
      /**
       * 优先级,数值越小优先级越高
       */
      int prio;
      /**
       * 下次可运行的时间,动态计算
       */
      long nexttime;

      public TaskObj(int _loopTimes, int _prio, ITask _task, Object _param) {
         loopTimes = _loopTimes;
         prio = _prio;
         task = _task;
         param = _param;
         setNextTime();
      }

      public void setNextTime() {
         nexttime = Calendar.getInstance().getTimeInMillis() + loopTimes;
      }

      public boolean isTimeTorun() {
         return nexttime <= Calendar.getInstance().getTimeInMillis();
      }
   }

   /**
    * 构造器
    */
   public MutiTasks() {
      taskList = new ArrayList<TaskObj>();
   }

   /**
    * 增加一个循环任务
    * @param loopTimes 循环时间间隔
    * @param prio 优先级别, 数字越小优先级别越高
    * @param task 任务过程
    * @param param 额外参数
    */
   public void addTask(int loopTimes, int prio, ITask task, Object param) {
      if (task == null) return;
      taskList.add(new TaskObj(loopTimes, prio, task, param));
   }

   /**
    * 删除一个循环任务
    * @param task 指定任务的引用
    */
   public void delTask(ITask task) {
      for (TaskObj o : taskList) {
         if (o.task == task) {
            taskList.remove(o);
            return;
         }
      }
   }

   /**
    * 执行任务。任务列表中找到可执行的优先级最高的任务执行
    * @param param 额外参数,目前没有任何用处
    * @return 没有要执行的任务返回false,否则返回true
    */
   @Override
   public boolean doWork(Object param) {
      TaskObj res = null;
      for (TaskObj o : taskList) {
         if (o.isTimeTorun()) {
            if (res == null)
               res = o;
            else if (res.prio > o.prio)
               res = o;
         }
      }
      if (res == null) return false;
      res.setNextTime();
      res.task.doWork(res.param);
      return true;
   }
}

package com.fcar.frameworks.tasks;

import android.os.Looper;

import com.fcar.frameworks.utils.L;

import java.util.Calendar;
import java.util.List;
import java.util.Stack;
import java.util.Vector;

/**
 * 任务管理器
 */
public class TaskManager {

   private TaskManager() {
   }

   /**
    * 任务的运行状态:正在运行,暂停,销毁
    */
   enum Cmd {
      CMD_RUN, CMD_PAUSE, CMD_DELETE
   }

   /**
    * 任务参数
    */
   static class Param {
      /**
       * 任务过程
       */
      ITask mTask;
      /**
       * 任务额外参数
       */
      Object mParam;
      /**
       * 任务当前状态
       */
      Cmd mCmd;
      /**
       * 任务前一个状态
       */
      Cmd mStatus;
      /**
       * 任务循环时间间隔
       */
      int loopTimes;
      /**
       * 任务下次执行的时间
       */
      long nexttime;

      public Param(int _looptimes, ITask task, Object param) {
         mTask = task;
         mParam = param;
         mCmd = Cmd.CMD_RUN;
         mStatus = Cmd.CMD_RUN;
         loopTimes = _looptimes;
      }

      /**
       * 设置下次应该运行的时间戳
       */
      public void setNextTime() {
         nexttime = Calendar.getInstance().getTimeInMillis() + loopTimes;
      }

      /**
       * 判断是否到了该执行的时间
       * @return
       */
      public boolean isTimeTorun() {
         return nexttime <= Calendar.getInstance().getTimeInMillis();
      }
   }

   /**
    * 任务栈,循环任务(LoopTask)值执行该栈栈顶的任务.
    */
   // Stack是线程安全的
   static Stack<Param> mStack = new Stack<Param>();

   /**
    * 执行循环任务的线程
    */
   static Thread mTLoop;

   /**
    * 辅助线程的任务列表,FIFO。主要用于向循环任务列表添加删除任务。因为这个List会被多个线程同时访问,使用Vector线程同步.
    * (Java似乎没有现成的线程同步的链表,所以暂时先用Vector吧)
    */
   static List<Param> mList = new Vector<Param>();

   /**
    * 将任务放入循环线程的辅助线程
    */
   static Thread tTTemp;

   /**
    * 任务线程中止的标志
    */
   static boolean isThreadEnd;

   /**
    * 辅助线程任务的模板
    */
   static class MyTask implements ITask {
      private Param mParam;

      public MyTask(Param param) {
         mParam = param;
      }

      @Override
      public boolean doWork(Object param) {
         Param p = mParam;
         TaskManager.addLoopTask_(p.loopTimes, p.mTask, p.mParam);
         return false;
      }
   }

   /**
    * 执行一个一般任务(一次性任务), 不等完成立即返回,可以在GUI内执行
    * @param task 要执行的任务
    * @param param 额外参数
    */
   public static void doTask(ITask task, Object param) {
      if (TaskManager.isInThread()) {
         L.e("TaskManager", "doTask already in Thread");
      }
      new CommThread(task, param);
   }

   /**
    * 添加一个循环任务到系统 并立即起作用
    * @param looptimes 循环时间间隔
    * @param task 循环任务的过程
    * @param param 额外参数
    */
   public static void addLoopTask(int looptimes, ITask task, Object param) {
      if (tTTemp == null) {
         isThreadEnd = false;
         tTTemp = new AuxiliaryThread();
         tTTemp.start();
      }
      // 将参数传入一个列表,供辅助线程使用,由辅助线程将任务加进任务栈
      //使用单独的线程执行,防止commthread的死锁
      Param p = new Param(looptimes, task, param);
      MyTask m = new MyTask(p);
      mList.add(new Param(0, m, null));
   }

   /**
    * 将循环任务放入循环任务栈栈顶
    * @param looptimes 循环任务的循环间隔时间,毫秒
    * @param task 循环任务循环的内容
    * @param param 额外参数
    */
   private static void addLoopTask_(int looptimes, ITask task, Object param) {
      if (task == null) return;
      if (mTLoop == null) {
         mTLoop = new LoopTaskThread();
         mTLoop.start();
      }
      // 避免在循环任务暂停期间(通常是因为要执行一次性任务)加入循环任务,从而导致循环任务和一次性任务同时运行
      CommThread.enterCriticalArea();
      // 用try,确保退出临界区
      try {
         loopTaskPause();
         mStack.push(new Param(looptimes, task, param));
         loopTaskResume();
      } finally {
         CommThread.exitCriticalArea();
      }
   }

   /**
    * 暂停循环任务,并等待循环任务真正暂停后返回。
    * <font color="red">如果在UI中,则不会等待而是立即返回</font>
    */
   public static void loopTaskPause() {
      if (mStack.size() == 0) return;

      if (!isInThread()) {
         mList.add(new Param(0, new ITask() {

            @Override
            public boolean doWork(Object param) {
               loopTaskPause();
               return false;
            }

         }, null));
         return;
      }

      mStack.peek().mStatus = Cmd.CMD_RUN;
      mStack.peek().mCmd = Cmd.CMD_PAUSE;
      while (mStack.peek().mStatus != Cmd.CMD_PAUSE) {
         TaskManager.Sleep(10);
      }
   }

   /**
    * 唤醒循环任务,并等待循环任务真正暂停后返回。
    * <font color="red">如果在UI中,则不会等待而是立即返回</font>
    */
   public static void loopTaskResume() {
      if (mStack.size() == 0) return;

      if (!isInThread()) {
         mList.add(new Param(0, new ITask() {

            @Override
            public boolean doWork(Object param) {
               loopTaskResume();
               return false;
            }

         }, null));
         return;
      }

      mStack.peek().mStatus = Cmd.CMD_PAUSE;
      mStack.peek().mCmd = Cmd.CMD_RUN;
      while (mStack.peek().mStatus != Cmd.CMD_RUN) {
         Sleep(10);
      }
   }

   /**
    * 当前线程休眠一段时间
    * @param ms 休眠多少毫秒
    */
   public static void Sleep(int ms) {
      try {
         Thread.sleep(ms);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
   }

   /**
    * 判断当前线程是不是UI线程
    * @return 如果不是UI线程,则返回true,否则返回false
    */
   public static boolean isInThread() {
      return Looper.getMainLooper() != Looper.myLooper();
   }

   /**
    * 撤销一个循环任务<br/>
    * <p>细节是:循环任务退栈,并等待完全退栈,最后(如果存在)将新栈顶任务标记为运行后返回</p>
    * <p><font color="red">注意,目前的实现中,你不可以在lookTask中调用该方法,这会造成死锁。</font></p>
    */
   public static void loopTaskBack() {
      if (mStack.size() == 0) {
         L.e("loopTaskBack", "Error:不可能的数据");
         return;
      }

      if (!isInThread()) {
         //L.w("退出发生在gui, loopTaskBack将立即返回,这可能会有风险,如果需要更长时间的退出动作,请new Thread来完成");
         mList.add(new Param(0, new ITask() {

            @Override
            public boolean doWork(Object param) {
               loopTaskBack();
               return false;
            }

         }, null));
         return;
      }

      Param p = mStack.peek();
      p.mStatus = Cmd.CMD_RUN;
      p.mCmd = Cmd.CMD_DELETE;

      while (p.mStatus != Cmd.CMD_DELETE) {
         Sleep(10);
      }
      if (mStack.size() != 0)
         mStack.peek().mCmd = Cmd.CMD_RUN;
   }

   /**
    * 停止辅助线程和循环任务线程,同时检查循环任务栈中的元素是否已经全部出栈
    */
   public static void close() {
      if (mStack.size() > 0) {
         L.e("TaskManager", "loop task 没有安全退出, 请检查你的程序,修复它.");
      }
      isThreadEnd = true;
   }

   /**
    * 添加循环任务的辅助线程,理论上,这个线程可能会长期空闲
    */
   private static class AuxiliaryThread extends Thread {
      @Override
      public void run() {
         while (!isThreadEnd) {
            if (!mList.isEmpty()) {
               Param p = mList.get(0);
               if (p.mTask != null) {
                  p.mTask.doWork(p.mParam);
               }
               mList.remove(0);
            } else {
               TaskManager.Sleep(10);
            }
         }
         mList.clear();
         tTTemp = null;
      }
   }

   /**
    * 实际执行循环任务的线程。循环任务线程是一个无限循环,每次取任务栈栈顶的任务执行。
    */
   private static class LoopTaskThread extends Thread {
      @Override
      public void run() {
         while (!isThreadEnd) {
            if (mStack.size() > 0) {
               Param p = mStack.peek();
               if (p.mCmd == Cmd.CMD_RUN && p.mTask != null) {
                  if (p.isTimeTorun()) {
                     p.setNextTime();            // 这么做似乎不太合理?是否应该改为完成以后延时?另外一种解决方案是,再增加一个字段设置两次循环之间至少等待多久
                     p.mTask.doWork(p.mParam);
                  }
                  p.mStatus = Cmd.CMD_RUN;
               } else if (p.mCmd == Cmd.CMD_DELETE) {
                  mStack.pop();
                  p.mStatus = Cmd.CMD_DELETE;
               } else
                  p.mStatus = Cmd.CMD_PAUSE;

               Sleep(1);
            } else
               Sleep(10);
         }
         mStack.clear();
         mTLoop = null;
      }
   }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值