Java 多线程 自定义线程辅助
之前的文章我介绍了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#版本一样。
Java 多线程 自定义线程辅助的更多相关文章
- java多线程与线程间通信
转自(http://blog.csdn.net/jerrying0203/article/details/45563947) 本文学习并总结java多线程与线程间通信的原理和方法,内容涉及java线程 ...
- Java多线程与线程池技术
一.序言 Java多线程编程线程池被广泛使用,甚至成为了标配. 线程池本质是池化技术的应用,和连接池类似,创建连接与关闭连接属于耗时操作,创建线程与销毁线程也属于重操作,为了提高效率,先提前创建好一批 ...
- Java 多线程:线程池
Java 多线程:线程池 作者:Grey 原文地址: 博客园:Java 多线程:线程池 CSDN:Java 多线程:线程池 工作原理 线程池内部是通过队列结合线程实现的,当我们利用线程池执行任务时: ...
- Java多线程之线程其他类
Java多线程之线程其他类 实际编码中除了前面讲到的常用的类之外,还有几个其他类也有可能用得到,这里来统一整理一下: 1,Callable接口和Future接口 JDK1.5以后提供了上面这2个接口, ...
- Java多线程之线程的通信
Java多线程之线程的通信 在总结多线程通信前先介绍一个概念:锁池.线程因为未拿到锁标记而发生的阻塞不同于前面五个基本状态中的阻塞,称为锁池.每个对象都有自己的锁池的空间,用于放置等待运行的线程.这些 ...
- Java多线程之线程的同步
Java多线程之线程的同步 实际开发中我们也经常提到说线程安全问题,那么什么是线程安全问题呢? 线程不安全就是说在多线程编程中出现了错误情况,由于系统的线程调度具有一定的随机性,当使用多个线程来访问同 ...
- Java多线程之线程的控制
Java多线程之线程的控制 线程中的7 种非常重要的状态: 初始New.可运行Runnable.运行Running.阻塞Blocked.锁池lock_pool.等待队列wait_pool.结束Dea ...
- Java多线程父子线程关系 多线程中篇(六)
有的时候对于Java多线程,我们会听到“父线程.子线程”的概念. 严格的说,Java中不存在实质上的父子关系 没有方法可以获取一个线程的父线程,也没有方法可以获取一个线程所有的子线程 子线程的消亡与父 ...
- 关于Java多线程的线程同步和线程通信的一些小问题(顺便分享几篇高质量的博文)
Java多线程的线程同步和线程通信的一些小问题(顺便分享几篇质量高的博文) 前言:在学习多线程时,遇到了一些问题,这里我将这些问题都分享出来,同时也分享了几篇其他博客主的博客,并且将我个人的理解也分享 ...
随机推荐
- 使用html5 地理位置技术 和 百度地图api查询当前位置
使用了 zepto 和 requirejs define(['zepto'],function($){ var geolocation = { init:function(config,onSuc ...
- Oracle EBS - Doc
Oracle EBS spec.: http://vianet/IT/IT%20Dept/IT%20Project%20Update2/Active%20Projects%20%20Manufactu ...
- Eclipse更新SDK速度慢,解决办法
在SDK Manager -> tools -> options中: HTTP Proxy Server: mirrors.neusoft.edu.cn HTTP Proxy Port: ...
- Google Chrome调试js入门
平常在开发过程中,经常会接触到前端页面.那么对于js的调试那可是家常便饭,不必多说.最近一直在用火狐的Firebug,但是不知道怎么的不好使了.网上找找说法,都说重新安装狐火浏览器就可以了,但是我安装 ...
- 支持向量机(SVM)复习总结
摘要: 1.算法概述 2.算法推导 3.算法特性及优缺点 4.注意事项 5.实现和具体例子 6.适用场合 内容: 1.算法概述 其基本模型定义为特征空间上的间隔最大的线性分类器,即支持向量机的学习策略 ...
- LInux MySQL 数据库 的一些操作
数据库安装: ………… 创建数据库连接新用户: 1.登录mysql #mysql -u root -p 2.新增用户 insert into mysql.user(Host,User,Password ...
- JQuery图片切换动画效果
由于博主我懒,所以页面画的比较粗糙,但是没关系,因为我主要讲的是如何实现图片动画切换. 思路:想必大家都逛过淘宝或者其他的一些网站,一般都会有图片动画切换的效果,那是怎样实现的呢?博主我呢,技术不是很 ...
- 关于ie11 的开发者工具
win7旗舰系统64为,更新ie11: 新安装了ie11浏览器,安装以后发现原来可以正常使用的开发者工具不能使用,提示 Imposible use F12 Developer Tools (Excep ...
- python 日期计算案例
一.计算两个日期内的所有月 def get_month_interval(start_str, end_str): start_year, start_month = list(map(int, st ...
- iOS点击状态栏回到顶部底层实现原理
在iOS开发中,苹果其实已经帮你实现了点击状态栏回到顶部这个功能,但我们在开发中会遇到点击不能回到顶部.其实这都和 ScrollView中的一个属性scrollsToTop有关,我们先看看苹果关于这个 ...