ScheduledExecutorService启动一个线程定期执行某个Task

需求:有一个远程文件synonym.txt,要求使用ScheduledExecutorService启动一个线程定期执行读取这个远程文件的内容并将其内容解析到内存中的一个数据结构中,使得这个内存中的数据结构永远可用。

远程txt的内容

出租车,出租汽车;
社保,社会保险;
医保,医疗保险;

参考elasticsearch-analysis-ik源码的写法,写了如下代码:

SynonymDic

public class SynonymDic {

    private static Logger LOGGER = LoggerFactory.getLogger(SynonymDic.class);

    private static SynonymDic singleton;

    public static SynonymDic getSingleton() {
        return singleton;
    }

    private List<Map<String, List<String>>> dic = new ArrayList<>();

    public List<Map<String, List<String>>> getDic() {
        return dic;
    }

    private static ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);

    private final static String PATH_DIC = "synonym.txt";

    public static synchronized SynonymDic initial() {
        if (singleton == null) {
            singleton = new SynonymDic();
            synchronized (SynonymDic.class) {
                singleton.loadSynonymDict();
                ///热更新功能以后有需要再启动
                Thread synonymThread = new Thread(new SynonymTask());
                synonymThread.setName("synonymTask");
                pool.scheduleAtFixedRate(synonymThread, 10, 60, TimeUnit.SECONDS);
            }
        }
        return singleton;
    }

    public void loadSynonymDict() {
        //首先将dic清空
        dic.clear();
        InputStream is = null;
        try {
            //使用不在jar中的资源文件
            File file = ResourceUtils.getFile("远程文件地址" + PATH_DIC);
            is = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"), 512);
            String theWord;
            do {
                theWord = br.readLine();
                if (theWord != null && !"".equals(theWord.trim())) {
                    //读到 出租车,出租汽车;
                    //去掉分号
                    theWord = theWord.substring(0, theWord.length() - 1);
                    String[] split = theWord.split(",");
                    List<String> list = new ArrayList<>();
                    for (String s :
                            split) {
                        list.add(s);
                    }
                    Map<String, List<String>> map = new HashMap<>(1);
                    map.put(theWord, list);
                    dic.add(map);
                }
            } while (theWord != null);
            LOGGER.info("共初始化同义词条数" + dic.size());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                    is = null;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

SynonymTask

public class SynonymTask implements Runnable {
    private static Logger LOGGER = LoggerFactory.getLogger(SynonymTask.class);
    @Override
    public void run() {
        LOGGER.info("Synonym Task loadSynonymDict 开始");
        SynonymDic.getSingleton().loadSynonymDict();
        LOGGER.info("Synonym Task loadSynonymDict 结束");
    }
}

这个模块是放在spring boot项目中的,我们期望在项目启动的时候,就读一次,之后每1分钟读取一次最新的内容

SysInit

@Component
public class SysInit implements ApplicationListener<ContextRefreshedEvent> {

    private static final Logger LOGGER = LoggerFactory.getLogger(SysInit.class);

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        LOGGER.info("初始化同义词list开始");
        SynonymDic.initial();
        LOGGER.info("初始化同义词list结束");
    }
}

比较好的实现了我们的需求。

需要注意的一点就是:这个是远程文件。如果是我们自己jar包里的文件,比如classpath下的synonym.txt文件,那么可以使用如下方法来读

public void loadSynonymDict() {
    //首先将dic清空
    dic.clear();
    //使用在jar中的资源文件
    Resource fileResource = new ClassPathResource(PATH_DIC);
    InputStream is = null;
    try {
        is = fileResource.getInputStream();
    } catch (FileNotFoundException e) {
        LOGGER.error(e.getMessage(), e);
    } catch (IOException e) {
        e.printStackTrace();
    }
    try {
        BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"), 512);
        String theWord;
        do {
            theWord = br.readLine();
            if (theWord != null && !"".equals(theWord.trim())) {
                //读到 出租车,出租汽车;
                //去掉分号
                theWord = theWord.substring(0, theWord.length() - 1);
                String[] split = theWord.split(",");
                List<String> list = new ArrayList<>();
                for (String s :
                        split) {
                    list.add(s);
                }
                Map<String, List<String>> map = new HashMap<>(1);
                map.put(theWord, list);
                dic.add(map);
            }
        } while (theWord != null);
        LOGGER.info("共初始化同义词条数"+dic.size());
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if (is != null) {
                is.close();
                is = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

但使用这种方式,是没办法在不重启项目的情况下读取最新内容的,因为这个文件是打在jar文件中的,所以启动不启动线程也就没啥意义了。在SysInit中初始化一次之后,dic就不会再变化了。

猜你喜欢

转载自blog.csdn.net/u013905744/article/details/82251470