定时器-单线程VS多线程
1、目标:根据某个标记状态或者任务都执行完成后,停止定时任务
开发环境:idea、jdk11
2、单线程方式
public static void main(String[] args) {
Stopwatch sw = Stopwatch.createStarted();
// 默认状态为true
AtomicBoolean flag = new AtomicBoolean(true);
var t1 = new Thread(() -> {
try {
System.out.println(flag + Thread.currentThread().getName());
Thread.sleep(1000);
System.out.println(flag + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}, "t1");
var t2 = new Thread(() -> {
try {
Thread.sleep(1200);
// 改为false,其他任务也无需执行
flag.set(false);
} catch (InterruptedException e) {
// e.printStackTrace();
// Thread.currentThread().interrupt();
}
}, "t2");
var t3 = new Thread(() -> {
try {
System.out.println(flag + Thread.currentThread().getName());
Thread.sleep(5000);
System.out.println(flag + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}, "t3");
t1.start();
t2.start();
t3.start();
Timer timer = new Timer();
// 同步器设置计数为1
final CountDownLatch countDownLatch = new CountDownLatch(1);
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("单线程定时器轮询");
if (!flag.get()) {
// 满足条件,计数清零
countDownLatch.countDown();
System.out.println("标记改变,结束定时器");
} else if (!t1.isAlive() && !t2.isAlive() && !t3.isAlive()) {
// 满足条件,计数清零
countDownLatch.countDown();
System.out.println("线程执行完成,结束定时器,查看标记状态" + flag.get());
}
}
}, 0, 300);
try {
System.out.println("countDownLatch wait");
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
// 关闭定时器
timer.cancel();
// 清空队列
timer.purge();
sw.stop();
log.info(String.valueOf(sw.elapsed(TimeUnit.MILLISECONDS)));
}
3、多线程方式
public static void main(String[] args) {
Stopwatch sw = Stopwatch.createStarted();
AtomicBoolean flag = new AtomicBoolean(true);
var t1 = new Thread(() -> {
try {
System.out.println(flag + Thread.currentThread().getName());
Thread.sleep(1000);
System.out.println(flag + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}, "t1");
var t2 = new Thread(() -> {
try {
Thread.sleep(1200);
flag.set(false);
} catch (InterruptedException e) {
// e.printStackTrace();
// Thread.currentThread().interrupt();
}
}, "t2");
var t3 = new Thread(() -> {
try {
System.out.println(flag + Thread.currentThread().getName());
Thread.sleep(5000);
System.out.println(flag + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}, "t3");
t1.start();
t2.start();
t3.start();
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
final var job = "job";
final Map<String, ScheduledFuture<?>> futures = new HashMap<>(1);
final CountDownLatch countDownLatch = new CountDownLatch(1);
var future = executor.scheduleAtFixedRate(() -> {
System.out.println("多线程定时器轮询");
if (!flag.get()) {
ScheduledFuture<?> f = futures.get(job);
// 关闭定时器
if (f != null) f.cancel(true);
// 释放countDownLatch.await
countDownLatch.countDown();
System.out.println("标记改变,结束定时器");
} else if (!t1.isAlive() && !t2.isAlive() && !t3.isAlive()) {
ScheduledFuture<?> f = futures.get(job);
// 关闭定时器
if (f != null) f.cancel(true);
// 释放countDownLatch.await
countDownLatch.countDown();
System.out.println("线程执行完成,结束定时器,查看标记状态" + flag.get());
}
}, 0, 100, TimeUnit.MILLISECONDS);
futures.put(job, future);
try {
System.out.println("countDownLatch wait");
countDownLatch.await();
sw.stop();
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
// 关闭线程池,最好放在finally中
executor.shutdown();
log.info(String.valueOf(sw.elapsed(TimeUnit.MILLISECONDS)));
}
到此,两种计时器实现轮询方式完成。