多线程进行同步数据

开发中会有场景需要对接第三方系统.第三方系统往往会提供一个中间库,然后我们系统读取中间库的数据,然后经过一系列的逻辑,把数据存到自己系统中. 在这里分享一种通过生产者,消费者模式进行数据同步,接近实时

主要思路: 一个生产者线程, 实时去中间库查询没有同步的数据.多个消费者,消费生产者生产的数据

                 1.一个生产者线程, 实时去中间库查询没有同步的数据

                 2.使用消费者对生产者生产的数据进行同步

                 3.记录下处理完成/处理失败的同步记录

/**
 * 同步中间库生产者.从中间库中查询数据
 */
public class Producer implements Runnable {

    private OwnerMiddleQueryService queryService;//查询中间库Service,可考虑抽成接口
    private LinkedBlockingQueue<Runnable> consumers;//消费者队列
    private ThreadPoolExecutor executor;//线程池


    public Producer(OwnerMiddleQueryService queryService, LinkedBlockingQueue<Runnable>
            consumers, ThreadPoolExecutor executor) {
        this.queryService = queryService;
        this.consumers = consumers;
        this.executor = executor;
    }

    @Override
    public void run() {
        while (true){
            List<OwnerMiddle> datas =  queryService.selectCount(50);
            if(datas != null && !datas.isEmpty()){
                try {
                    Consumer consumer = (Consumer) consumers.take();//从队列中取出一个消费者
                    queryService.updateStatus(datas,STATUS.HANDLING);//更改状态字段或记录操作记录
                    consumer.setDatas(datas);//查询出的数据给到消费者中
                    executor.execute(consumer);//执行消费者操作
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    queryService.updateStatus(datas,STATUS.FAIL);//记录下同步失败的记录

                }
            }else {
                try {
                    TimeUnit.SECONDS.sleep(3);//防止一直查询空的结果
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}
/**
 * 同步中间库消费者.消费生产者的数据
 */
public class Consumer implements Runnable{

    private List<OwnerMiddle> datas;//待同步数据
    private OwnerMiddleDealService ownerMiddleDealService;//用于同步数据的Service
    private LinkedBlockingQueue<Runnable> consumers;//消费者队列

    public Consumer(OwnerMiddleDealService ownerMiddleDealService, LinkedBlockingQueue<Runnable>
            consumers) {
        this.ownerMiddleDealService = ownerMiddleDealService;
        this.consumers = consumers;
    }

    @Override
    public void run() {
        try{
            ownerMiddleDealService.dealData(datas);//进行同步数据:把数据插入到自己系统的库中,并记录下同步记录
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                consumers.put(this);//消费者用完后放回队列
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    public List<OwnerMiddle> getDatas() {
        return datas;
    }

    public void setDatas(List<OwnerMiddle> datas) {
        this.datas = datas;
    }
}

由于我们需要在系统启动时即开启该线程.故我们监听ContextRefreshedEvent事件进行触发.注意, 不能监听ContextStartedEvent事件,该事件是在所有的bean初始化之前的.这样我们一些Service,Mapper对象都会无法注入.

@Component
public class SyncMiddleComponent implements ApplicationListener<ContextRefreshedEvent> {

    private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 5L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(20)); //线程池
    private LinkedBlockingQueue<Runnable> runnables = new LinkedBlockingQueue<>(10);//任务队列


    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        OwnerMiddleQueryService middleQueryService = new OwnerMiddleQueryService();
        OwnerMiddleDealService middleDealService = new OwnerMiddleDealService();
        for (int i = 0; i < 10; i++) {
            //10个消费者
            try {
                runnables.put(new Consumer(middleDealService,runnables));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Producer producer = new Producer(middleQueryService, runnables, threadPoolExecutor);
        new Thread(producer).start();//开启生产者线程
    }
}

OwnerMiddleDealService  和 OwnerMiddleQueryService的方法的实现都是些业务逻辑.主要逻辑已标明在注释中.具体的逻辑则要根据系统的业务进行编码.

另外值得注意的是.由于在线程中是不能直接注入Spring管理的bean的.因为线程没有被Spring管理.此处可以自定义一个工具类,实现 ApplicationContextAware进行手动获取bean.可在类的构造器中进行获取.

具体可以参考:https://blog.csdn.net/fubo1990/article/details/79648766

发布了53 篇原创文章 · 获赞 5 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_40085888/article/details/100678624
今日推荐