使用多线程创建一个定时任务

此生再无相见时 提交于 2019-12-01 10:02:07

业务场景:

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的配置与维护,另方面减少频繁查数据库,减少数据库压力,此种方式显得更轻量

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!