之前的文章我介绍了C#版本的多线程和自定义线程处理器。
接下来我们来看看Java版本的呢
java 的线程和C#的线程有点区别,java的线程没有是否是后台线程一说,具体原因是java的线程是jvm的c++代码模拟线程,而C#的线程也是C++模拟线程。但是区别在于C#的线程会基于系统的线程。
C# 的 Thread.IsBackground;
这里唯一的区别在于,C#开启线程如果是非后台线程即便是你关闭了程序,如果不是强制退出进程的情况下。线程还会继续运行,知道垃圾回收机制强制回收。如果设置了后台线程标识,关闭程序就直接退出。
java没有一说。
java线程有分组和底层线程ID一说。C#没有。
java的线程可以自定义线程运行接口 Runnable 或者 重写线程run()方法。
其实这些都是大同小异的,区别性不大。
java线程的基础知识,到处都是,我不在BB
直接开始整体吧~!
/** * 线程模型 * * @author 失足程序员 * @Blog http://www.cnblogs.com/ty408/ * @mail 492794628@qq.com * @phone 13882122019 * */ public class ThreadModel extends Thread { private static final Logger log = Logger.getLogger(TaskModel.class); private static int threadID = 0; private static final Object SYN_OBJECT = new Object(); private long tid; /** * 任务列表 线程安全的任务列表 */ protected final List<TaskModel> taskQueue = Collections.synchronizedList(new LinkedList<TaskModel>()); //false标识删除线程 private boolean runing = true; public ThreadModel(ThreadGroup group) { this(group, "无名"); } public ThreadModel(ThreadGroup group, String name) { super(group, name); synchronized (SYN_OBJECT) { threadID++; tid = threadID; } } @Override public long getId() { return this.tid; } /** * 增加新的任务 每增加一个新任务,都要唤醒任务队列 * * @param runnable */ public void addTask(TaskModel runnable) { synchronized (taskQueue) { taskQueue.add(runnable); /* 唤醒队列, 开始执行 */ taskQueue.notify(); } } public void setRuning(boolean runing) { this.runing = runing; } @Override public void run() { while (runing && ThreadManager.getInstance().isRunning()) { TaskModel r = null; while (taskQueue.isEmpty() && runing && ThreadManager.getInstance().isRunning()) { try { /* 任务队列为空,则等待有新任务加入从而被唤醒 */ synchronized (taskQueue) { taskQueue.wait(500); } } catch (InterruptedException ie) { log.error(ie); } } synchronized (taskQueue) { /* 取出任务执行 */ if (runing && ThreadManager.getInstance().isRunning()) { r = taskQueue.remove(0); } } if (r != null) { /* 执行任务 */ //r.setSubmitTimeL(); long submitTime = System.currentTimeMillis(); try { r.run(); } catch (Exception e) { log.error("工人<“" + Thread.currentThread().getName() + "”> 执行任务<" + r.getID() + "(“" + r.getName() + "”)> 遇到错误: " + e); e.printStackTrace(); } long timeL1 = System.currentTimeMillis() - submitTime; long timeL2 = System.currentTimeMillis() - r.getSubmitTime(); if (timeL1 <= 100L) { log.info("工人<“" + Thread.currentThread().getName() + "”> 完成了任务:" + r.toString() + " 执行耗时:" + timeL1 + " 提交耗时:" + timeL2); } else if (timeL1 <= 1000L) { log.info("工人<“" + Thread.currentThread().getName() + "”> 长时间执行 完成任务:" + r.toString() + " “考虑”任务脚本逻辑 耗时:" + timeL1 + " 提交耗时:" + timeL2); } else if (timeL1 <= 4000L) { log.info("工人<“" + Thread.currentThread().getName() + "”> 超长时间执行完成 任务:" + r.toString() + " “检查”任务脚本逻辑 耗时:" + timeL1 + " 提交耗时:" + timeL2); } else { log.info("工人<“" + Thread.currentThread().getName() + "”> 超长时间执行完成 任务:" + r.toString() + " “考虑是否应该删除”任务脚本 耗时:" + timeL1 + " 提交耗时:" + timeL2); } r = null; } } log.error("线程结束, 工人<“" + Thread.currentThread().getName() + "”>退出"); } @Override public String toString() { return "Thread{" + "tid=" + tid + ",Name=" + this.getName() + '}'; } }
这里创建我们自定义的线程模型,有两点值得注意的是,
protected final List<TaskModel> taskQueue = Collections.synchronizedList(new LinkedList<TaskModel>());
synchronized (taskQueue) { taskQueue.add(runnable); /* 唤醒队列, 开始执行 */ taskQueue.notify(); } synchronized (taskQueue) { taskQueue.wait(500); }
这里我们同样没有使用Thread.Sleep();对线程进行暂停,同样使用的是 taskQueue.wait();来进行线程暂停,这是因为当任务队列为空的时候,需要暂停线程。
当新的任务被放进来的时候,又必须立即开始执行任务。
为了防止线程永久暂停,设置的是500毫秒,这样我们需要关闭程序(ThreadManager.getInstance().isRunning()==false)停止线程时候他会自定停止。
辅助键值对存储器
/** * 辅助键值对存储 * * @author 失足程序员 * @Blog http://www.cnblogs.com/ty408/ * @mail 492794628@qq.com * @phone 13882122019 */ public class ObjectAttribute extends HashMap<String, Object> { private static final long serialVersionUID = -5320260807959251398L; /** * 调用此方法 删除值是需要保证存在key值和value值 否则空指针报错 * * @param <T> * @param key * @param clazz * @return * @deprecated 需要保证存在key值和value值 否则空指针报错 慎重 */ @Deprecated public <T extends Object> T remove(String key, Class<T> clazz) { Object obj = this.remove(key); return (T) obj; } /** * 如果未找到也返回 null * * @param key * @return */ public String getStringValue(String key) { if (this.containsKey(key)) { return this.get(key).toString(); } return null; } /** * 如果未找到也返回 0 * * @param key * @return */ public int getintValue(String key) { if (this.containsKey(key)) { return (int) (this.get(key)); } return 0; } /** * 如果未找到也返回 null * * @param key * @return */ public Integer getIntegerValue(String key) { if (this.containsKey(key)) { return (Integer) (this.get(key)); } return null; } /** * 如果未找到也返回 0 * * @param key * @return */ public long getlongValue(String key) { if (this.containsKey(key)) { return (long) (this.get(key)); } return 0; } /** * 如果未找到也返回 null * * @param key * @return */ public Long getLongValue(String key) { if (this.containsKey(key)) { return (Long) (this.get(key)); } return null; } /** * 如果未找到也返回 0 * * @param key * @return */ public float getfloatValue(String key) { if (this.containsKey(key)) { return (float) (this.get(key)); } return 0; } /** * 如果未找到也返回 null * * @param key * @return */ public Float getFloatValue(String key) { if (this.containsKey(key)) { return (Float) (this.get(key)); } return null; } /** * 如果未找到也返回 false * * @param key * @return */ public boolean getbooleanValue(String key) { if (this.containsKey(key)) { return (boolean) (this.get(key)); } return false; } /** * 如果未找到也返回 null * * @param key * @return */ public Boolean getBooleanValue(String key) { if (this.containsKey(key)) { return (Boolean) (this.get(key)); } return null; } @Override public Object clone() { return super.clone(); //To change body of generated methods, choose Tools | Templates. } }
任务执行模型
/** * 任务模型 * * @author 失足程序员 * @Blog http://www.cnblogs.com/ty408/ * @mail 492794628@qq.com * @phone 13882122019 * */ public abstract class TaskModel { private static final Logger log = Logger.getLogger(TaskModel.class); private long ID; private String Name; //运行时数据 private ObjectAttribute runAttribute = new ObjectAttribute(); public TaskModel(long ID, String Name) { this.ID = ID; this.Name = Name; this.runAttribute.put("submitTime", System.currentTimeMillis()); } public TaskModel() { this(0, "无名"); } public long getSubmitTime() { return this.runAttribute.getlongValue("submitTime"); } public ObjectAttribute getRunAttribute() { return runAttribute; } public void setRunAttribute(ObjectAttribute runAttribute) { this.runAttribute = runAttribute; } public long getID() { return ID; } public String getName() { return Name; } public abstract void run(); @Override public String toString() { return "TaskModel{" + "ID=" + ID + ", Name=" + Name + ", runAttribute=" + runAttribute + '}'; } }
接下来我们测试一下
ThreadModel threadModel = new ThreadModel(new ThreadGroup("Test"), "Test"); threadModel.start(); threadModel.addTask(new TaskModel() { @Override public void run() { System.out.println("TaskModel Test"); } });
执行结果
TaskModel Test [04-24 17:31:26:0223:INFO : sz.network.threadpool.TaskModel:97 行] -> 工人<“Test”> 完成了任务:TaskModel{ID=0, Name=无名, runAttribute={submitTime=1429867886219}} 执行耗时:0 提交耗时:4
我们看到居然有提交耗时,,别奇怪,,因为在某些情况下,线程的从暂停状态到唤醒状态需要消耗时间的,系统不可能有那么多空闲资源,收到你的命令马上就放弃一切事情执行你的命令。
我们调试运行时可以看见当前程序所有线程,以及分组情况(我使用的是NetBeans IDE 8.0.2 开发工具)
接下来我们来构建一下。后台线程池,
/** * 后台线程池 * * @author 失足程序员 * @Blog http://www.cnblogs.com/ty408/ * @mail 492794628@qq.com * @phone 13882122019 */ class BackThread { private static final Logger log = Logger.getLogger(BackThread.class); private final ThreadGroup threadGroup = new ThreadGroup(ThreadManager.getGlobeThreadGroup(), "后台执行器"); /* 任务列表 */ private final List<TaskModel> taskQueue = Collections.synchronizedList(new LinkedList<TaskModel>()); private final BackThreadRunnable backThreadRunnable = new BackThreadRunnable(); public BackThread() { int threadcountI = 10; for (int i = 1; i <= threadcountI; i++) { Thread thread = new Thread(threadGroup, backThreadRunnable, "后台线程-" + i); thread.start(); } log.info("---初始化后台线程池--线程数量:" + threadcountI + "------------"); } /** * 增加新的任务 每增加一个新任务,都要唤醒任务队列 * * @param newTask */ public void addTask(TaskModel newTask) { synchronized (taskQueue) { taskQueue.add(newTask); /* 唤醒队列, 开始执行 */ taskQueue.notify(); } } final class BackThreadRunnable implements Runnable { /** * 循环执行任务 */ @Override public void run() { while (ThreadManager.getInstance().isRunning()) { TaskModel r = null; synchronized (taskQueue) { while (taskQueue.isEmpty() && ThreadManager.getInstance().isRunning()) { try { /* 任务队列为空,则等待有新任务加入从而被唤醒 */ taskQueue.wait(500); } catch (InterruptedException ie) { log.error(ie); } } /* 取出任务执行 */ if (ThreadManager.getInstance().isRunning()) { r = taskQueue.remove(0); } } if (r != null) { /* 执行任务 */ //r.setSubmitTimeL(); long submitTime = System.currentTimeMillis(); try { r.run(); } catch (Exception e) { e.printStackTrace(); log.error("工人<“" + Thread.currentThread().getName() + "”> 执行任务<" + r.getID() + "(“" + r.getName() + "”)> 遇到错误: " + e); } long timeL1 = System.currentTimeMillis() - submitTime; long timeL2 = System.currentTimeMillis() - r.getSubmitTime(); if (timeL1 <= 100L) { log.info("工人<“" + Thread.currentThread().getName() + "”> 完成了任务:" + r.toString() + " 执行耗时:" + timeL1 + " 提交耗时:" + timeL2); } else if (timeL1 <= 1000L) { log.info("工人<“" + Thread.currentThread().getName() + "”> 长时间执行 完成任务:" + r.toString() + " “考虑”任务脚本逻辑 耗时:" + timeL1 + " 提交耗时:" + timeL2); } else if (timeL1 <= 4000L) { log.info("工人<“" + Thread.currentThread().getName() + "”> 超长时间执行完成 任务:" + r.toString() + " “检查”任务脚本逻辑 耗时:" + timeL1 + " 提交耗时:" + timeL2); } else { log.info("工人<“" + Thread.currentThread().getName() + "”> 超长时间执行完成 任务:" + r.toString() + " “考虑是否应该删除”任务脚本 耗时:" + timeL1 + " 提交耗时:" + timeL2); } r = null; } } log.error("线程结束, 工人<“" + Thread.currentThread().getName() + "”>退出"); } } }
以及定时器线程处理器
/** * 定时器线程 * * @author 失足程序员 * @Blog http://www.cnblogs.com/ty408/ * @mail 492794628@qq.com * @phone 13882122019 */ class TimerThread extends ThreadModel { private static final Logger log = Logger.getLogger(TimerThread.class); public TimerThread() { super(ThreadManager.getGlobeThreadGroup(), "全局定时器线程"); this.start(); } @Override public void run() { while (ThreadManager.getInstance().isRunning()) { while (ThreadManager.getInstance().isRunning() && taskQueue.isEmpty()) { try { /* 任务队列为空,则等待有新任务加入从而被唤醒 */ synchronized (taskQueue) { taskQueue.wait(200); } } catch (InterruptedException ie) { } } ArrayList<TaskModel> taskModels; synchronized (taskQueue) { //队列不为空的情况下 取出队列定时器任务 taskModels = new ArrayList<>(taskQueue); } if (!taskModels.isEmpty()) { for (TaskModel task : taskModels) { TimerTask timerEvent = (TimerTask) task; int execCount = timerEvent.getRunAttribute().getintValue("Execcount"); long lastTime = timerEvent.getRunAttribute().getlongValue("LastExecTime"); long nowTime = System.currentTimeMillis(); if (nowTime > timerEvent.getStartTime() //是否满足开始时间 && (nowTime - timerEvent.getSubmitTime() > timerEvent.getIntervalTime())//提交以后是否满足了间隔时间 && (timerEvent.getEndTime() <= 0 || nowTime < timerEvent.getEndTime()) //判断结束时间 && (nowTime - lastTime >= timerEvent.getIntervalTime())) //判断上次执行到目前是否满足间隔时间 { //提交执行 ThreadManager.getInstance().addTask(timerEvent.gettID(), timerEvent); //记录 execCount++; timerEvent.getRunAttribute().put("Execcount", execCount); timerEvent.getRunAttribute().put("LastExecTime", nowTime); } nowTime = System.currentTimeMillis(); //判断删除条件 if ((timerEvent.getEndTime() > 0 && nowTime < timerEvent.getEndTime()) || (timerEvent.getActionCount() > 0 && timerEvent.getActionCount() <= execCount)) { taskQueue.remove(task); } } } try { //定时器, 执行方式 间隔 4ms 执行一次 把需要处理的任务放到对应的处理线程 Thread.sleep(4); } catch (InterruptedException ex) { } } log.error("线程结束, 工人<“" + Thread.currentThread().getName() + "”>退出"); } @Override public void addTask(TaskModel task) { if (((TimerTask) task).isIsStartAction()) { try { task.run(); } catch (Exception e) { log.error("工人<“" + Thread.currentThread().getName() + "”> 执行任务<" + task.getID() + "(“" + task.getName() + "”)> 遇到错误: " + e); e.printStackTrace(); } } super.addTask(task); } }
定时器线程执行任务模型
/** * 定时器执行器 * * @author 失足程序员 * @Blog http://www.cnblogs.com/ty408/ * @mail 492794628@qq.com * @phone 13882122019 */ public abstract class TimerTask extends TaskModel { private static final long serialVersionUID = -8331296295264699207L; /** * 线程ID */ private long tID; /** * 开始执行的时间 */ private long startTime; /** * 是否一开始执行一次 */ private boolean isStartAction; /** * 结束时间 */ private long endTime; /** * 执行次数 */ private int actionCount; /** * 间隔执行时间 */ private int intervalTime; /** * * @param tID 指定执行线程 * @param startTime 指定开始时间 * @param isStartAction 是否一开始就执行一次 * @param endTime 指定结束时间 * @param actionCount 指定执行次数 * @param intervalTime 指定间隔时间 * @param ID * @param Name */ public TimerTask(long tID, long startTime, boolean isStartAction, long endTime, int actionCount, int intervalTime, long ID, String Name) { super(ID, Name); this.tID = tID; this.startTime = startTime; this.isStartAction = isStartAction; this.endTime = endTime; this.actionCount = actionCount; this.intervalTime = intervalTime; } /** * 指定任务的开始执行时间 * * @param tID 指定执行线程 * @param startTime 指定开始时间 * @param isStartAction 是否一开始就执行一次 * @param actionCount 指定执行次数 * @param intervalTime 指定间隔时间 * @param ID * @param Name */ public TimerTask(long tID, long startTime, boolean isStartAction, int actionCount, int intervalTime, long ID, String Name) { this(tID, startTime, isStartAction, 0, actionCount, intervalTime, ID, Name); } /** * 指定结束时间已结束时间为准,执行次数不一定够 * * @param tID 指定执行线程 * @param isStartAction 是否一开始就执行一次 * @param endTime 指定结束时间 * @param actionCount 指定执行次数 * @param intervalTime 指定间隔时间 * @param ID * @param Name */ public TimerTask(long tID, boolean isStartAction, long endTime, int actionCount, int intervalTime, long ID, String Name) { this(tID, 0, isStartAction, endTime, actionCount, intervalTime, ID, Name); } /** * 指定开始时间,和结束时间 * * @param tID 指定执行线程 * @param startTime 指定开始时间 * @param endTime 指定结束时间 * @param intervalTime 指定间隔时间 * @param ID * @param Name */ public TimerTask(long tID, long startTime, long endTime, int intervalTime, long ID, String Name) { this(tID, startTime, false, endTime, -1, intervalTime, ID, Name); } /** * 指定执行线程,指定执行次数,指定间隔时间 * * @param tID 指定执行线程 * @param actionCount 指定执行次数 * @param intervalTime 指定间隔时间 * @param ID * @param Name */ public TimerTask(long tID, int actionCount, int intervalTime, long ID, String Name) { this(tID, 0, false, 0, actionCount, intervalTime, ID, Name); } /** * 指定的执行次数和间隔时间 * * @param actionCount 指定执行次数 * @param intervalTime 指定间隔时间 */ public TimerTask(int actionCount, int intervalTime) { this(0, 0, false, 0, actionCount, intervalTime, 0, "无名"); } /** * 提交后指定的时间以后执行一次 * * @param intervalTime 指定间隔时间 */ public TimerTask(int intervalTime) { this(0, 0, false, 0, 1, intervalTime, 0, "无名"); } public long gettID() { return tID; } public void settID(long tID) { this.tID = tID; } public long getStartTime() { return startTime; } public void setStartTime(long startTime) { this.startTime = startTime; } public boolean isIsStartAction() { return isStartAction; } public void setIsStartAction(boolean isStartAction) { this.isStartAction = isStartAction; } public long getEndTime() { return endTime; } public void setEndTime(long endTime) { this.endTime = endTime; } public int getActionCount() { return actionCount; } public void setActionCount(int actionCount) { this.actionCount = actionCount; } public int getIntervalTime() { return intervalTime; } public void setIntervalTime(int intervalTime) { this.intervalTime = intervalTime; } }
创建一个线程管理器
/** * 线程管理器 * * @author 失足程序员 * @Blog http://www.cnblogs.com/ty408/ * @mail 492794628@qq.com * @phone 13882122019 * */ public class ThreadManager { private static final Logger log = Logger.getLogger(ThreadManager.class); private static final ThreadGroup GlobeThreadGroup = new ThreadGroup("全局线程"); private static final ThreadGroup lsThreadGroup = new ThreadGroup("零时线程"); private static ThreadManager instance = new ThreadManager(); private static final HashMap<Long, ThreadModel> workThreadMaps = new HashMap<>(0); public static ThreadManager getInstance() { return instance; } public static ThreadGroup getGlobeThreadGroup() { return GlobeThreadGroup; } private final BackThread backThread = new BackThread(); private final TimerThread timerThread = new TimerThread(); //服务器是否运行状态标识 private boolean running = true; public boolean isRunning() { return running; } public void StopServer() { running = false; } public long addThread(ThreadModel thread) { workThreadMaps.put(thread.getId(), thread); thread.start(); return thread.getId(); } public long getThread(ThreadGroup threadGroup, String workName) { return addThread(new ThreadModel(threadGroup, workName)); } public long getThread(String workName) { return addThread(new ThreadModel(lsThreadGroup, workName)); } public boolean delete(long threadID) { ThreadModel get = workThreadMaps.remove(threadID); if (get != null) { get.setRuning(false); return true; } return false; } public void addTask(long threadID, TaskModel task) { if (workThreadMaps.containsKey(threadID)) { workThreadMaps.get(threadID).addTask(task); } else { addBackTask(task); } } public void addTimerTask(TimerTask task) { timerThread.addTask(task); } /** * * @param task */ public void addBackTask(TaskModel task) { backThread.addTask(task); } }
重新测试一下
public static void main(String[] args) { long thread = ThreadManager.getInstance().getThread("Test"); ThreadManager.getInstance().addBackTask(new TaskModel() { @Override public void run() { System.out.println("addBackTask"); } }); ThreadManager.getInstance().addTimerTask(new TimerTask(5, 100) { @Override public void run() { System.out.println("TimerTask 5 100"); } }); ThreadManager.getInstance().addTask(thread, new TaskModel() { @Override public void run() { System.out.println("Thread test"); } }); }
[04-24 17:40:23:0883:INFO : sz.network.threadpool.BackThread:37 行] -> ---初始化后台线程池--线程数量:10------------ addBackTask Thread test [04-24 17:40:23:0888:INFO : sz.network.threadpool.BackThread:89 行] -> 工人<“后台线程-10”> 完成了任务:TaskModel{ID=0, Name=无名, runAttribute={submitTime=1429868423887}} 执行耗时:0 提交耗时:0 [04-24 17:40:23:0888:INFO : sz.network.threadpool.TaskModel:97 行] -> 工人<“Test”> 完成了任务:TaskModel{ID=0, Name=无名, runAttribute={submitTime=1429868423887}} 执行耗时:1 提交耗时:1 TimerTask 5 100 [04-24 17:40:23:0988:INFO : sz.network.threadpool.BackThread:89 行] -> 工人<“后台线程-9”> 完成了任务:TaskModel{ID=0, Name=无名, runAttribute={LastExecTime=1429868423988, submitTime=1429868423887, Execcount=1}} 执行耗时:0 提交耗时:101 TimerTask 5 100 [04-24 17:40:24:0088:INFO : sz.network.threadpool.BackThread:89 行] -> 工人<“后台线程-8”> 完成了任务:TaskModel{ID=0, Name=无名, runAttribute={LastExecTime=1429868424088, submitTime=1429868423887, Execcount=2}} 执行耗时:0 提交耗时:201 TimerTask 5 100 [04-24 17:40:24:0189:INFO : sz.network.threadpool.BackThread:89 行] -> 工人<“后台线程-7”> 完成了任务:TaskModel{ID=0, Name=无名, runAttribute={LastExecTime=1429868424189, submitTime=1429868423887, Execcount=3}} 执行耗时:0 提交耗时:302 TimerTask 5 100 [04-24 17:40:24:0289:INFO : sz.network.threadpool.BackThread:89 行] -> 工人<“后台线程-6”> 完成了任务:TaskModel{ID=0, Name=无名, runAttribute={LastExecTime=1429868424289, submitTime=1429868423887, Execcount=4}} 执行耗时:0 提交耗时:402 TimerTask 5 100 [04-24 17:40:24:0389:INFO : sz.network.threadpool.BackThread:89 行] -> 工人<“后台线程-9”> 完成了任务:TaskModel{ID=0, Name=无名, runAttribute={LastExecTime=1429868424389, submitTime=1429868423887, Execcount=5}} 执行耗时:0 提交耗时:502
调试查看线程信息
Java版本的自定义线程处理器就算完成了。
功能和实现基本和C#版本一样。