concurrent在线文档:
http://www.cjsdn.net/Doc/JDK50/java/util/concurrent/Executors.html
http://www.cjsdn.net/Doc/JDK50/java/util/concurrent/ScheduledExecutorService.html
java.util.concurrent包主要接口和类:
Executor:具体Runnable任务的执行者。
ExecutorService:一个线程池管理者,其实现类有多种,我会介绍一部分。我们能把Runnable,Callable提交到池中让其调度。
Semaphore:一个计数信号量
ReentrantLock:一个可重入的互斥锁定 Lock,功能类似synchronized,但要强大的多。
Future:是与Runnable,Callable进行交互的接口,比如一个线程执行结束后取返回的结果等等,还提供了cancel终止线程。
BlockingQueue:阻塞队列。
CompletionService: ExecutorService的扩展,可以获得线程执行结果的
CountDownLatch:一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
CyclicBarrier:一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点
Future:Future 表示异步计算的结果。
ScheduledExecutorService :一个 ExecutorService,可安排在给定的延迟后运行或定期执行的命令。
下面主要介绍ScheduledExecutorService
ScheduledExecutorService
一个 ExecutorService,可安排在给定的延迟后运行或定期执行的命令。
schedule 方法使用各种延迟创建任务,并返回一个可用于取消或检查执行的任务对象。scheduleAtFixedRate 和 scheduleWithFixedDelay 方法创建并执行某些在取消前一直定期运行的任务。
用 Executor.execute(java.lang.Runnable) 和 ExecutorService 的 submit 方法所提交的命令,通过所请求的 0 延迟进行安排。
schedule 方法中允许出现 0 和负数延迟(但不是周期),并将这些视为一种立即执行的请求。
所有的 schedule 方法都接受相对 延迟和周期作为参数,而不是绝对的时间或日期。将以 Date 所表示的绝对时间转换成要求的形式很容易。
例如,要安排在某个以后的日期运行,可以使用:schedule(task, date.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS)。
但是要注意,由于网络时间同步协议、时钟漂移或其他因素的存在,因此相对延迟的期满日期不必与启用任务的当前 Date 相符。
Executors 类为此包中所提供的 ScheduledExecutorService 实现提供了便捷的工厂方法。
样例01:
许多长时间运行的应用有时候需要定时运行任务完成一些诸如统计、优化等工作,比如在电信行业中处理用户话单时,需要每隔1分钟处理话单;网站每天凌晨统计用户访问量、用户数;大型超时凌晨3点统计当天销售额、以及最热卖的商品;每周日进行数据库备份;公司每个月的10号计算工资并进行转帐等,这些都是定时任务。通过 java的并发库concurrent可以轻松的完成这些任务,而且非常的简单。
package com.amg.test; import static java.util.concurrent.TimeUnit.SECONDS; import java.util.Date; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; public class TestScheduledThread { public static void main(String[] args) { final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2); final Runnable beeper01 = new Runnable() { int count = 0; @Override public void run() { System.out.println(new Date() + " beep01 " + (++count)); } }; final Runnable beeper02 = new Runnable() { int count = 0; @Override public void run() { System.out.println(new Date() + " beep02 " + (++count)); } }; // 任务1:1秒钟后运行,并每隔2秒运行一次 final ScheduledFuture beeperHandle01 = scheduler.scheduleAtFixedRate(beeper01, 1, 2, SECONDS); // 任务2:2秒钟后运行,并每次在上次任务运行完后等待5秒后重新运行 final ScheduledFuture beeperHandle02 = scheduler.scheduleWithFixedDelay(beeper02, 2, 5, SECONDS); // 30秒后结束关闭任务,并且关闭Scheduler scheduler.schedule(new Runnable() { @Override public void run() { beeperHandle01.cancel(true); beeperHandle02.cancel(true); scheduler.shutdown(); } }, 30, SECONDS); } }
为了退出进程,上面的代码中加入了关闭Scheduler的操作。而对于24小时运行的应用而言,是没有必要关闭Scheduler的。
样例02:
说明:下面的例子可实现以上同一功能:
package com.amg.test; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class TestScheduledThreadPoolExecutor { private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static void main(String[] args) { ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1); System.out.println("thread start!!!"); // scheduleAtFixedRate(Runnable对象,run方法执行的时候延迟?秒执行自己的方法,run方法执行时间间隔) exec.scheduleAtFixedRate(new Runnable() {// 每隔一段时间就触发异常 @Override public void run() { // 执行自己的方法 System.out.println("RuntimeException"); } }, 3000, 5000, TimeUnit.MILLISECONDS); exec.scheduleAtFixedRate(new Runnable() {// 每隔一段时间打印系统时间,证明两者是互不影响的 @Override public void run() { // 执行自己的方法 System.out.println(sdf.format(new Date())); } }, 2000, 5000, TimeUnit.MILLISECONDS); } }