使用多線程(newSingleThreadScheduledExecutor)創建一個定時任務


業務場景:

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的配置與維護,另方面減少頻繁查數據庫,減少數據庫壓力,此種方式顯得更輕量


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM