業務場景:
1、項目中很多場景下使用到了定時任務,一般采用job的方式
2、一些輕量級的定時操作,如定時查數據庫,將數據加載到內存中,不用頻繁查數據庫,可以采用多線程(newSingleThreadScheduledExecutor)的方式實現顯得更輕量高效
廢話不多說,直接上代碼
(1)、創建一個接口
package com.search.vst.search.service; /** * @desc 商圈 * @author zhanhao */ import com.search.vst.search.beans.vo.PoiBusinessAreaVo; public interface PoiBusinessAreaService { PoiBusinessAreaVo getPoiBusinessArea(String cityId, String keyWords); void updatePoiBusinessAreaConfig(); }
(2)、創建一個實現類
package com.search.vst.search.service.impl; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; import javax.annotation.PostConstruct; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.search.vst.search.ENV; import com.search.vst.search.beans.vo.PoiBusinessAreaVo; import com.search.vst.search.service.PoiBusinessAreaService; import com.search.vst.search.service.WordTaggingDataService; @Service("poiBusinessAreaService") public class PoiBusinessAreaServiceImpl implements PoiBusinessAreaService { private static Log log=LogFactory.getLog(PoiBusinessAreaServiceImpl.class); @Autowired private WordTaggingDataService wordTaggingDataService; private ReentrantLock trieBuildLock=new ReentrantLock(); private volatile List<PoiBusinessAreaVo> poiBusinessAreaList= new ArrayList<PoiBusinessAreaVo>(); private static ScheduledExecutorService ex=Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder().setNameFormat("PoiBusinessAreaService_trie_worker_%d").build()); @PostConstruct protected void init() { ex.scheduleWithFixedDelay(new Runnable() { @Override public void run() { try { updatePoiBusinessAreaConfig(); } catch (Exception e) { log.warn("updatePoiBusinessAreaConfig init error " + e.getMessage()); } } }, 0, 2, TimeUnit.MINUTES); updatePoiBusinessAreaConfigForFirstTime(); } /** * 因為項目在重啟的過程中,如果依賴的search_calculate也在重啟,那么調用dubbo會失敗,導致tire數構建失敗,這里啟動一個線程做多次嘗試 */ private void updatePoiBusinessAreaConfigForFirstTime() { Thread loopInitThread = new Thread(new Runnable() { @Override public void run() { // 延遲一分鍾執行 try { TimeUnit.MINUTES.sleep(1); } catch (InterruptedException e1) { } log.info(Thread.currentThread().getName() + " start!"); int maxTryTimes = 10; int tryInterval = 20; while (maxTryTimes > 0 && CollectionUtils.isEmpty(poiBusinessAreaList)) { try { maxTryTimes--; updatePoiBusinessAreaConfig(); } catch (Exception e) { if (ENV.isArk()) { log.warn("try to update config error,times:" + maxTryTimes + "@error " + e); } else { log.error("try to update config error,times:" + maxTryTimes, e); } } finally { try { TimeUnit.SECONDS.sleep(tryInterval); } catch (InterruptedException e) { log.error("interupted ,times:" + maxTryTimes, e); } } } log.info(Thread.currentThread().getName() + " finish!"); } }); loopInitThread.setName("poi_buildTrie_loopInitThread"); loopInitThread.start(); } private void buildTrie() { List<PoiBusinessAreaVo> poiBusinessAreas = wordTaggingDataService.getPoiBusinessArea(); this.poiBusinessAreaList = poiBusinessAreas; } @Override public void updatePoiBusinessAreaConfig() { boolean lockRequired = false; try { lockRequired = trieBuildLock.tryLock(10, TimeUnit.SECONDS); if (lockRequired) { buildTrie(); } else { log.warn("lockRequired unsuccessful"); } } catch (InterruptedException e) { log.error("lockRequired fail", e); } finally { if (lockRequired) { trieBuildLock.unlock(); } } } @Override public PoiBusinessAreaVo getPoiBusinessArea(String cityDistrictId, String keyWords) { if (CollectionUtils.isNotEmpty(this.poiBusinessAreaList)) { for (PoiBusinessAreaVo poiBusinessAreaVo : this.poiBusinessAreaList) { if (Objects.equals(cityDistrictId, poiBusinessAreaVo.getCityId()) && Objects.equals(keyWords, poiBusinessAreaVo.getPoiBusinessArea())) { return poiBusinessAreaVo; } } } return null; } }
總結:該業務場景下,一方面減少job的配置與維護,另方面減少頻繁查數據庫,減少數據庫壓力,此種方式顯得更輕量