项目中有个自动归档的功能,自动给过期的个人单位等数据进行归档处理。
基本的思路是这样的:使用另外一个线程,专门处理定时归档这件事,但是看了一下Timer实现,发现有好多缺点。
测试1:
<pre name="code" class="java">public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new TimerTask() { public void run() { System.out.println(System.currentTimeMillis()); System.out.println(Thread.currentThread()); try { Thread.sleep(2000); }catch (InterruptedException e) { e.printStackTrace(); } }, 0); timer.schedule(new TimerTask() { public void run() { System.out.println(System.currentTimeMillis()); System.out.println(Thread.currentThread()); } }, 1); }
1436275510043 Thread[Timer-0,5,main] 1436275512044 Thread[Timer-0,5,main]
测试2:
public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new TimerTask() { public void run() { System.out.println("任务1执行-"); throw new RuntimeException("抛个异常"); } }, 0); timer.schedule(new TimerTask() { public void run() { System.out.println("任务2执行-"); } }, 1); }结果如下:
任务1执行- Exception in thread "Timer-0" java.lang.RuntimeException: 抛个异常 at a.thread.timer.Test$1.run(Test.java:12) at java.util.TimerThread.mainLoop(Timer.java:555) at java.util.TimerThread.run(Timer.java:505)说明这个一旦线程出现错误,后面的任务就全没了,不怎么可靠。
与线程池相比,线程池的自愈能力是非常不错的:
线程池的作用:
1.减少创建和销毁线程的次数,每个线程都可以重复利用,可执行多个任务。
2.集中管理线程,可以根据系统所能承受的能力来设置线程池中线程的数目,防止开了过多的线程而是服务器运行缓慢(每个线程需要大约1M内存)。
<pre name="code" class="java">public class WorkThread extends Thread { // 方便控制线程开关 private boolean flag = true; @Override public synchronized void run() { while (flag) { while (ThreadQueue.getQueue().hasMoreTask()) { if (!flag) { return; } ThreadQueue.getQueue().nextTask().run(); if (!flag){ System.out.println(Thread.currentThread()+"任务执行完毕,停止运行------------不再睡眠"); return; } } try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } public void close() { flag = false; } }
package a.thread.threadpool; public class ThreadPool { private int maxThreadCount = 120; private int defaultThreadCount = 100; private WorkThread[] threads; ThreadPool(int threadCount) { this.defaultThreadCount = threadCount; } ThreadPool() { } { threads = new WorkThread[maxThreadCount]; for (int i = 0; i < defaultThreadCount; i++) { threads[i] = new WorkThread(); } } static ThreadPool obtain() { return new ThreadPool(); } /** * 返回空闲的线程 * */ WorkThread getFreeThread() { for (int i = 0; i < defaultThreadCount; i++) { Thread.State state = threads[i].getState(); if (state.equals(Thread.State.NEW) || state.equals(Thread.State.WAITING)) { return threads[i]; } } if (defaultThreadCount < maxThreadCount) { System.out.println("线程数不够,准备创建新的,当前数量为->" + defaultThreadCount); threads[defaultThreadCount] = new WorkThread(); return threads[defaultThreadCount++]; } return null; } /** * 关闭所有的线程 * */ public void closeAll() { for (WorkThread thread : threads) { if (thread != null) thread.close(); } } }
package a.thread.threadpool; /** * 线程池管理器 * */ public class ThreadPoolManager { private ThreadQueue queue = ThreadQueue.getQueue(); private ThreadPool threadPool = ThreadPool.obtain(); private boolean work = true; /** * 执行一个线程 * */ public void execute(Runnable task) { if (task == null) { throw new RuntimeException(); } if (!work) { System.out.println("线程池已准备关闭,无法加入新的任务"); return; } queue.addTask(task); WorkThread workThread = threadPool.getFreeThread(); if (workThread != null) { if (workThread.getState().equals(Thread.State.NEW)) { workThread.start(); } else if (workThread.getState().equals(Thread.State.WAITING)) { synchronized (workThread) { workThread.notify(); } } } } public void cancel() { work = false; threadPool.closeAll(); } }
package a.thread.threadpool; import java.util.LinkedList; import java.util.Queue; /** * 线程队列 * */ public class ThreadQueue { private static ThreadQueue threadQueue=new ThreadQueue(); public static ThreadQueue getQueue() { return threadQueue; } private Queue<Runnable> tasks; { tasks = new LinkedList<Runnable>(); } public synchronized boolean hasMoreTask() { return !tasks.isEmpty(); } public synchronized Runnable nextTask() { return tasks.poll(); } public void addTask(Runnable task) { tasks.offer(task); } }
让线程不关闭,然后等待任务进来执行任务,这个肯定是要用回调的。
怎么让线程不死掉,遇到任务的时候又能执行?
我想到了2个方法:
1.用while(true)一直绕回圈,检查队列中的任务,有就执行,没有就接着跑,这个就像是android中的Looper
2.用obj.wait(),等待任务来了,来一个唤醒他一下。
但是whilt(true)我一直看他不爽,因为一直跑没任务的任务,总感觉好浪费内存,wait的字面意思就舒服多了。。。。这个完全是个人观点
wait()用的是本地方法,没法看到源代码,网上也没找到whilt(true)与wait到底哪个更好的说法,,
其实我用了wait是因为Timer里面他用的是wait。。。
可是android的Looper他用的while(true)
后来想了想,应该是这样的(也是个人观点):
android的Looper负责处理界面的显示相关,要求实时性非常高,一个线程一直跑,而且界面操作本来就频繁,所有说这个用while(true)一直查找队列里的任务是很好的选择,而wait与notify线程间的通信可能需要一点时间,没while(true)来的直接。
而我们一般用的普通任务,就拿项目中的自动归档,可能是一天才执行一次,那24小时让他while(true)跑着也不是一个意思,然他睡着,等到任务时间到了再让他起来干活。
while(true)与wait问题到此为止。。
写的时候遇到的问题:
一开始写的时候,从队列中取任务,并且扔给工作线程任务是在ThreadPoolManger中执行的,后来测试的时候发现个问题:这个execute方法阻塞了,因为这里把队列中的任务取出来执行,如果里面的任务耗时很久,那调用execute方法的线程就阻塞住了。
当时的想法就是我再写一个线程,把这阻塞的这一部分代码放到另外一个线程里面。这个线程专门处理将队列中的任务拿到工作线程中执行的操作。但是这个有点麻烦,锁加来加去的。
直接把队列放到workThread中,让线程自己去处理,自己阻塞去,工作线程阻塞了就说明任务还没做完,任务做好了接着检查queue中有没有任务,有就接着做,这里记得给队列加个锁。这样就行了。
还有关闭线程池,其中也遇到了关闭了池后程序无法结束的问题,因为ThreadPoolManager中,调用了ThreadPool的closeAll()方法,这个时候已经运行的任务好像是要结束了。不过这时候如果新任务加入,可能又有新的线程去干活了,有线程活着程序就不会关闭,我们都懂得。所以说在关闭的同时要防止其他任务再进来。