java工具类-优雅等待所有任务完成再停机

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class AppUtil {

    //0 没任务在执行 > 1 有任务在执行 ,奇数时app已结束。
    //最大只支持到30个不同任务。
    //同一个任务只支持单线程。
    public final AtomicInteger TASK_RUN = new AtomicInteger(0);

    //a必须是2的n次方且n>1
    public boolean addTask(int a) {
        if(a > 1 && (a & (a - 1)) == 0) {
            //不允许程序已经结束了,还在跑任务。
            if(TASK_RUN.get() % 2 == 1) {
                return false;
            }
            //尝试添加任务
            if(TASK_RUN.addAndGet(a) % 2 == 1) {
                //任务添加失败,回滚。
                deleteTask(a);
                return false;
            }
            return true;
        }
        throw new RuntimeException("传入的a不是大于1且是2的n次方的数:" + a);
    }

    public void deleteTask(int a) {
        TASK_RUN.addAndGet(-a);
    }

    public void stopApp() {
        TASK_RUN.addAndGet(1);
    }

    /**
     * 必须要保证所有任务都要在指定时间内能结束。
     */
    public void waitTaskFinally(int tryLimit) {
        int i = 0;
        while (true) {
            if(TASK_RUN.get() == 1) {
                break;
            }
            if(i++ >= tryLimit) {
                break;
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                //如果这里被中断的概率大,就直接不往外抛异常。
                throw new RuntimeException(e);
            }
        }
    }

    public void run(Runnable run, int a) {
        boolean lock = addTask(a);
        try {
            if(!lock) return;
            run.run();
        } finally {
            if(lock) deleteTask(a);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        AppUtil app = new AppUtil();
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
        pool.scheduleAtFixedRate(() -> {
            app.run(() -> System.out.println("处理任务one: " + System.currentTimeMillis()), 2);
        }, 1, 1, TimeUnit.SECONDS);
        pool.scheduleAtFixedRate(() -> {
            app.run(() -> System.out.println("处理任务two: " +System.currentTimeMillis()), 4);
        }, 1, 2, TimeUnit.SECONDS);
        Thread.sleep(10000);
        app.stopApp();
        app.waitTaskFinally(50);
        System.out.println("结束:"+ System.currentTimeMillis() + " " + app);
        pool.shutdown();
    }

    @Override
    public String toString() {
        return "AppUtil{" +
               "TASK_RUN=" + TASK_RUN +
               '}';
    }
}

使用方式:

public class ActivityApplication {
	public static final AppUtil APP_UTIL = new AppUtil();

	public static void main(String[] args) {
		SpringApplication.run(ActivityApplication.class, args);
		log.info("=============system default timeZone: {}", TimeZone.getDefault());
		log.info("=============system default zoneId: {}", ZoneId.systemDefault());
		Runtime.getRuntime().addShutdownHook(new Thread(() -> {
			log.info("收到终止信号,当前标记:appStop: {}", APP_UTIL);
			APP_UTIL.stopApp();
			//分50次,共等5秒。
			//这里如果能保证了在运行中的任务在5秒内能结束的话,就不会被强杀。
			APP_UTIL.waitTaskFinally(50);
			log.info("收到终止信号,最新标记:appStop: {}", APP_UTIL);
		}));

	}

}

 

posted @ 2025-08-06 14:10  数学与IT  阅读(6)  评论(0)    收藏  举报