守护线程的使用
最近有个需求,当一个线程开始时,需要实时判断这个线程是否存在,去修改一些值。
场景:.现在需要迁移一个公司的数据,异步操作。在系统中公司的数据如果在迁移,不能重复迁移。
// 发起迁移数据的进口,这里因为这个操作不常用,所以没有用线程池。
// 原因是,守护线程的限制。线程池,只是把线程放回线程池,没有销毁,所以守护线程无法判断到这个线程已经完成。
// 如果要使用线程池,可以在心跳守护线程中手动设置一个值控制
Thread thread= new Thread(new Runnable() { @Override public void run() { try { HeartbeatHelper.start(2, comId + "_" + module + "_trans"); dataTansService.dataTransfer(comId, module, instance); } catch (Exception e) { LOGGER.error("迁移公司[" + comId + "]的数据失败,原因:" + e.getMessage(), e); } } }); thread.start();
public class HeartbeatHelper { /** * 心跳缓存关键字前缀 */ private static final String ERP_HEARTBEAT_KEY_PREFIX = "HEARTBEAT_KEY_PREFIX_"; private static CacheFacade cacheFacade = ApplicationContextManager.getBean(CacheFacade.class); /** * 启动心跳 * @param key 关键字 */ public static void start(String key) { new HeartbeatDaemon(key).start(); } /** * 判断心跳线程是否存在 */ public static boolean isLive(String key) { return PlatformUtils.hasText(cacheFacade.get(wrapKey(key))); } public static String wrapKey(String key) { return ERP_HEARTBEAT_KEY_PREFIX + key; } /** * 启动心跳 * @param minute 心跳频率,单位分钟 * @param key 关键字 */ public static HeartbeatDaemon start(int minute, String key) { HeartbeatDaemon daemon = new HeartbeatDaemon(minute,key); daemon.start(); return daemon; } public static class HeartbeatDaemon extends Thread { /** * 守护的对象:即为创建该守护线程的线程对象 */ private final Thread guard; private static final String NAME_PREFIX = "guarding_"; /** * 心跳频率为10分钟1次 */ private static final int HEART_RATE = 10; /** * 心跳频率,单位分钟 */ private final int rate; /** * 缓存关键字 */ private final String key; private Logger logger = LoggerFactory.getLogger(HeartbeatHelper.class); public HeartbeatDaemon(int minute, String key) { this.rate = minute * CommonPlatformConstant.SECOND_MINUTE; this.key = key; setDaemon(true); guard = Thread.currentThread(); setName(NAME_PREFIX + guard.getName()); } public HeartbeatDaemon(String key) { this(HEART_RATE, key); } @Override public void run() { while (guard.isAlive()) {
// 守护的线程活着的时候做的事情 try {
cacheFacade.set(wrapKey(key), DateUtils.formatDateTime(new Date()), rate); } catch (Exception e) { logger.error("更新心跳失败:" + e.getMessage(), e); } try { // 休眠时间应该小于键的有效时间 Thread.sleep((rate -1) * CommonPlatformConstant.SECOND_OF_MILLISECOND); } catch (InterruptedException e) { logger.error("更新心跳休眠失败:" + e.getMessage(), e); } } } } }