在任务调度池功能加入之前,可以使用java.util.Timer来实现定时功能,Timer的优点在于简单易用,但由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或者异常会影响到后面的任务。
例子
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Slf4j(topic = "ch.ThreadPoolTest06")
public class ThreadPoolTest06 {
public static void main(String[] args) {
// method01();
// method02();
method03();
}
public static void method01() {
Timer timer = new Timer();
TimerTask task01 = new TimerTask() {
@Override
public void run() {
log.debug("task 01 running");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
};
TimerTask task02 = new TimerTask() {
@Override
public void run() {
log.debug("task 02 running");
}
};
log.debug("任务进入规划");
//预期情况就是任务一执行完之后,任务二才会执行
timer.schedule(task01, 1000);
timer.schedule(task02, 1000);
}
public static void method02() {
Timer timer = new Timer();
TimerTask task01 = new TimerTask() {
@Override
public void run() {
log.debug("task 01 running");
int i = 1 / 0;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
};
TimerTask task02 = new TimerTask() {
@Override
public void run() {
log.debug("task 02 running");
}
};
log.debug("任务进入规划");
//预期情况就是任务一执行出现异常,那么任务二就不会执行
timer.schedule(task01, 1000);
timer.schedule(task02, 1000);
}
//预期是同时执行,任务调度线程池在线程数目够的情况下会并发执行,而且一个线程的执行成功与否不会影响另一个线程的执行结果
public static void method03() {
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(2);
threadPool.schedule(() -> {
log.debug("任务一执行");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}, 1, TimeUnit.SECONDS);
threadPool.schedule(() -> {
log.debug("任务二执行");
}, 1, TimeUnit.SECONDS);
}
}
任务调度线程池的其他用法
任务调度线程池还可以利用scheduleAtFixedRate来实现定时且周期性的执行某些任务
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Slf4j(topic = "ch.ThreadPoolTest07")
public class ThreadPoolTest07 {
static Runnable task01 = new Runnable() {
@Override
public void run() {
log.debug("执行");
}
};
static Runnable task02 = new Runnable() {
@Override
public void run() {
log.debug("执行");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
};
public static void main(String[] args) {
// method01();
method02();
}
public static void method01() {
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(2);
//传入的是task01,预期就是准备一秒后开始执行,然后每隔一秒执行一次
log.debug("准备周期性运行");
threadPool.scheduleAtFixedRate(task01, 1, 1, TimeUnit.SECONDS);
}
public static void method02() {
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(2);
//传入的是task01,预期就是准备一秒后开始执行,然后每隔两秒执行一次,这是因为任务执行时间大于间隔时间,所以间隔变化了两秒
log.debug("准备周期性运行");
threadPool.scheduleAtFixedRate(task02, 1, 1, TimeUnit.SECONDS);
}
}
整个线程池的线程数固定,当任务数多于线程数时,会放入无界队列排队,任务执行完毕,这些线程也不会被释放,可以用来周期性的执行一些任务。
线程池处理异常的方式
一般有两种方式,第一种是主动的捕捉异常;第二种是使用future获取异常
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@Slf4j(topic = "ch.ThreadPoolTest08")
public class ThreadPoolTest08 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// method1();
method2();
}
//主动捕捉异常
public static void method1() {
ExecutorService pool = Executors.newFixedThreadPool(1);
pool.submit(() -> {
log.debug("任务一");
try {
int i = 1 / 0;
} catch (Exception e) {
log.error("error:" + e);
}
});
}
//使用future获取异常
public static void method2() throws ExecutionException, InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(1);
Future<Boolean> result = pool.submit(() -> {
log.debug("task1");
int i = 1 / 0;
return true;
});
log.debug("result:{}", result.get());
}
}
应用之定时任务
假设有一个需求是要在每周一下午五点执行一个任务,如何利用线程池来实现呢?
import lombok.extern.slf4j.Slf4j;
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
//如何在每周二下午17:00五点定时执行一个任务
@Slf4j(topic = "ch.ThreadPoolTest09")
public class ThreadPoolTest09 {
static final int beginHour = 20;
public static void main(String[] args) {
ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(1);
//任务
Runnable task = new Runnable() {
@Override
public void run() {
log.debug("任务执行");
}
};
// 初始间隔时间,有两种情况
// 第一种情况是当前时间在周二下午五点之前
// 第二种情况是当前时间在周二下午五点之后
LocalDateTime now = LocalDateTime.now();
//返回当周的周二下午五点
LocalDateTime time = now.withHour(beginHour).withMinute(0).withSecond(0).withNano(0).with(DayOfWeek.WEDNESDAY);
//在周二下午五点之前的情况
if (now.compareTo(time) > 0) {
time = time.plusWeeks(1);
}
long initialDelay = Duration.between(now, time).toMillis();
//一周的时间
long gap = 1000 * 60 * 60 * 24 * 7;
scheduledPool.scheduleAtFixedRate(task, initialDelay, gap, TimeUnit.MILLISECONDS);
}
}
标签:java,log,16,void,util,线程,import,任务调度,public
From: https://www.cnblogs.com/wbstudy/p/16754218.html