精华内容
下载资源
问答
  • 通过这次对超市会员管理系统的开发,使我掌握了一个完善的系统需要经过五个开发步骤:系统规划、系统分析、系统设计、系统实施和系统维护。锻炼我发现问题、分析问题和解决问题的能力,熟练的掌握和运用系统工程思想...
  • 之前学习定时任务线程池(ScheduledThreadPoolExecutor)时发现它主要依赖线程池和它的静态内部类DelayedWorkQueue实现。而DelayedWorkQueue就是一种延迟队列,今天学习是并发包提供的延迟队列(DelayQueue)。延迟队列...

    之前学习定时任务线程池(ScheduledThreadPoolExecutor)时发现它主要依赖线程池和它的静态内部类DelayedWorkQueue实现。而DelayedWorkQueue就是一种延迟队列,今天学习是并发包提供的延迟队列(DelayQueue)。

    延迟队列说明

    延迟队列提供的功能是在指定时间点才能获取队列元素的功能,队列最前面的元素是最优先执行的元素

    列举一下使用场景可能能够更加好理解,比如缓存系统的设计,缓存中的对象,指定了过期时间,到了过期时间就需要从缓存中移出;在比如任务调度系统,要准确在任务规定的时间点执行任务。这些场景如果我们不使用延迟队列,就必须不同的遍历所有缓存、任务然后判断是否需要移除缓存、执行任务。

    而延迟队列则不需要不停的扫描缓存、任务,它能够实现能够实现在准确的时间点去执行任务

    接下来我们梳理一下缓存准时移除的实现,首先我们知道每个缓存的过期时间,就可以计算出每个缓存过期的时间戳,我们首先根据过期时间戳作为比较放到优先级队列(上一篇文章介绍的优先级队列)中,然后从优先级队列获取缓存,肯定是获取到最先需要过期的缓存,判断缓存是否到了过期时间,如果没到则把线程阻塞(过期时间戳与当前时间戳的差值),一定时间后线程自动唤醒,再次验证发现缓存刚好到期,可以移除缓存。

    同样定时任务的准时执行也一样,只不过是把缓存过期的时间戳换成定时任务下次执行时间戳作为比较依据。

    通过分析发现要实现这个功能需要一个优先级队列,保存的元素要指定移除队列的时间戳

    DelayQueue属性介绍

    从上一步分析得出延迟队列必须拥有优先级队列的功能,同时保存的元素要有确定移除队列的时间,那么我们来看DelayQueue具体实现,基本属性源码如下图:

    0e08544500eaf29aca32d055b5d24407.png

    可以看到它利用优先级队列q用来保存数据,那么就拥有了优先级队列的全部功能。

    接着看它所能存储的元素都必须继承Delayed,查看Delayed源码发现它继承了Comparable接口,并且声明了方法"long getDelay(TimeUnit unit);",这个方法的说明翻译过来是:以给定的时间单位返回与此对象关联的剩余延迟。它可以直接得出对象剩余延迟,就像缓存的剩余时间,就可以执行获取到对象的线程阻塞时间。

    那么继承至Delayed的对象就同时拥有了优先级队列需要的Comparable的实现和对象剩余延迟执行的时间

    DelayQueue关键实现

    直接看take方法的实现,源码如下图:

    145e8ce82a6f839a46dcc735a3f7475e.png

    只要上一篇文章弄懂了优先级队列,在看延迟队列的代码就很简单了。首先利用的是优先级队列获取元素,然后调用getDelay(Delayed接口声明的)方法判断是否阻塞以及阻塞时间

    可以看到第一个线程进来了如果发现节点为null则是不限阻塞时间的阻塞,而后面进来的线程如果发现leader不为null也是直接阻塞,后面的线程可以通过leader线程执行完后唤醒,那么leader线程是什么时候唤醒呢?

    leader无限阻塞的原因是队列中没有数据,所以要唤醒肯定就是添加数据的地方,在offer方法保存元素成功后会验证队列最前面的是不是刚刚保存的元素,如果是则会调用available.signal();唤醒线程,代码比较简单就不贴出来了。

    延迟队列最佳实践

    延迟队列要说最佳实践就要说到前面提交的定时任务了,在之前分析定时任务线程池ScheduledThreadPoolExecutor提到过,所以我们直接来看ScheduledThreadPoolExecutor中的实现,关键源码如下图:

    9c509f3a02707dcc9c29a8c09beca3fd.png

    每个任务在放到任务队列前都会设置下次执行时间time,如上图通过time实现了getDelay和compareTo方法,这样一个线程池就可以保存多个定时任务,每个任务在执行完后会重置time然后继续放到线程池的优先级队列中,就是如此的简单的实现了定时任务。

    总结

    在弄懂了优先级队列后在看延迟队列还是很简单的,无非是在优先级队列的基础上扩展了一丁点的功能,如何实现定时任务也就很简单了。

    Java程序员日常学习笔记,如理解有误欢迎各位交流讨论!

    3deb250c1bc5e9e654e4b382f95e2798.png
    展开全文
  • 但是这些活动做多做久了,很容易发现这些活动往往都有相同的触达体系、任务体系及奖励体系。 为加快产品迭代,减轻技术人员负担,提示系统安全稳定性。独立活动中台、任务中台、营销触达中心迫在眉睫。本文主要阐述...

    背景:用户群体不断增加,部门不断扩展,产品经理提出越来越多的活动运营需求,程序员不堪重负。但是这些活动做多做久了,很容易发现这些活动往往都有相同的触达体系、任务体系及奖励体系。
          为加快产品迭代,减轻技术人员负担,提示系统安全稳定性。独立活动中台、任务中台、营销触达中心迫在眉睫。本文主要阐述任务中台搭建流程。
     

    解决问题:

              1 构建更易扩展的任务场景数据库设计及代码设计;
              2 庞大会员体系(4亿+)快速支撑任务开启、任务校验所涉及的并发及压力问题;
              3 依靠服务器及数据库水平扩容保证更大压力下的任务中台支撑能力;
    技术方案:

              1 采用策略模式设计任务中台,校验不同任务完成状况,并更新用户任务记录表。
                数据库设计见下图:
              2 使用redis并发锁,通过锁定用户userID 3秒解决并发问题。使用hystrix熔断降级,保证服务能力。
              3 任务调度系统采用SaturnJob分布式调度系统,数据库为Mycat+mysql集群,通过Saturn分片参数,执行不同分片数据库数据,支撑服务能力水平提升。
    实施:

           1 数据库设计见下图:

    2 依靠策略模式核心代码:

    /**
    * 策略类
    */
    public abstract class QuestStrategy {
    
        @Autowired
        private TaskRecordManager taskRecordManager;
    
        /**
         * 对接关联系统校验任务是否完成
         *
         * @return
         */
        public abstract boolean checkQuestIsComplete(TaskRecord record);
    
    
    }
    public enum QuestHandlerEnum {
    
        //等级提升
        MEMBER_GRADE_QUEST("0502", ServiceBean.getSpringContext().getBean(MemGradeStrategy.class)),
        //商品兑换
        MEMBER_EXCHANGE_QUEST("0503", ServiceBean.getSpringContext().getBean(MemExchangeStrategy.class)),
    
        //页面浏览
        BROWSE_QUEST("06", ServiceBean.getSpringContext().getBean(PageStrategy.class)),
    
        //页面点击
        CLICK_QUEST("07", ServiceBean.getSpringContext().getBean(PageStrategy.class));
    
        private String type;
    
        private QuestStrategy questStrategy;
    
        QuestHandlerEnum(String type, QuestStrategy quest) {
            this.type = type;
            this.questStrategy = quest;
        }
    
        public String getType() {
            return type;
        }
    
        public void setType(String type) {
            this.type = type;
        }
    
        public QuestStrategy getQuestStrategy() {
            return questStrategy;
        }
    
    }
    public class QuestHandler {
    
        private static final Logger logger = LoggerFactory.getLogger(LoggerType.COMMON);
    
        static Map<String, QuestStrategy> strategyMap = new HashMap<>();
    
        static {
            for(QuestHandlerEnum questEnum : QuestHandlerEnum.values()){
                strategyMap.put(questEnum.getType(),questEnum.getQuestStrategy());
            }
        }
    
        public static QuestStrategy getStrategy(String type) {
            return strategyMap.get(type);
        }
    
        /**
         * 校验任务是否完成
         * @return
         */
        public static TaskRecord checkQuest(String type, TaskRecord taskRecord,boolean isJob){
            try {
                QuestStrategy questStrategy = getStrategy(type);
    
                //校验任务完成状态
                boolean isFinish;
    
                if(isJob){
                    isFinish = questStrategy.checkQuestIsCompleteJob(taskRecord);
                }else{
                    isFinish = questStrategy.checkQuestIsComplete(taskRecord);
                }
                //未完成 将任务列表返回
                if(!isFinish){
                    return taskRecord;
                }
    
                //任务完成  通过userId 和ID更新任务状态
                taskRecord.setStatus(Constant.RecordStatus.FINISHED);
                questStrategy.insertOrUpdateTask(taskRecord);
                return taskRecord;
    
            } catch (Exception e) {
                logger.error("checkQuest error ", e);
            }
            return taskRecord;
        }
    }
    /**
    * 等级提升实现类
    */
    @Service
    public class MemGradeStrategy extends QuestStrategy {
    
        @Autowired
        private IntegralServiceImpl integralService;
    
        private static final Logger logger = LoggerFactory.getLogger(LoggerType.COMMON);
    
        @Override
        public boolean checkQuestIsComplete(TaskRecord record) {
            //查询会员等级变化情况
            QueryGradeChangeDTO queryGradeChangeDTO = new QueryGradeChangeDTO();
            queryGradeChangeDTO.setFlag("1");
            queryGradeChangeDTO.setUserId(record.getUserId());
            queryGradeChangeDTO.setActivityStartTm(record.getStartTm());
            MemberGradeChangeVO memberGradeChange = integralService.getChangeInfo(queryGradeChangeDTO);
            if(null == memberGradeChange) {
                return false;
            }
    
            updateTaskProcess(record,String.valueOf(memberGradeChange.getGradeCode()));
    
            String value = getTargetString(record.getRule());
           return memberGradeChange.getGradeCode().compareTo(value)>=0 && memberGradeChange.getGradeCode().compareTo(memberGradeChange.getLstGradeCode())>0 && value.compareTo(memberGradeChange.getLstGradeCode())>0;
        }
    
    }
    /**
    * 分布式调度任务执行
    */
    @Component
    public class UpdateTaskStatusJob extends AbstractSaturnJavaJob {
    
       private static final int mysqlNodeCount = 128;
    
        private static final Logger logger = LoggerFactory.getLogger(LoggerType.COMMON);
    
        ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
    
        private final static List<Integer> slicingList = new ArrayList<>();
    
        @Autowired
        TaskRecordManager taskRecordManager;
    
        @Autowired
        TaskRecordService taskRecordService;
    
        static {
            for (int i = 1; i <= mysqlNodeCount; i++) {
                slicingList.add(i);
            }
        }
    
        /**
         * Java作业处理入口
         *
         * @param jobName         作业名
         * @param shardItem       分片项
         * @param shardParam      分片参数
         * @param shardingContext 其它参数信息
         * @return 返回执行结果
         * @throws InterruptedException 注意处理中断异常
         */
        @Override
        public SaturnJobReturn handleJavaJob(String jobName, Integer shardItem, String shardParam,
                                             SaturnJobExecutionContext shardingContext) {
            logger.info("UpdateTaskStatusJob定时任务执行--开始");
            long start = System.currentTimeMillis();
            SaturnJobReturn jr = new SaturnJobReturn();
            try {
                List<Integer> shardIds;
                if (StringUtils.isBlank(shardParam)) {
                    shardIds = slicingList;
                } else {
                    Integer piece = Integer.valueOf(shardParam);
                    shardIds = slicingList.stream().collect(Collectors.groupingBy(e->e%shardingContext.getShardingTotalCount())).get(piece);
                }
                for (Integer shardId : shardIds) {
                    processShard(shardId);
                }
                jr.setReturnCode(SaturnSystemReturnCode.SUCCESS);
                logger.info("UpdateTaskStatusJob定时任务执行--结束 耗时:{}ms", System.currentTimeMillis() - start);
            }catch (Exception e){
                logger.error("UpdateTaskStatusJob定时任务执行 error:{}",slicingList,e);
                jr.setReturnCode(SaturnSystemReturnCode.SYSTEM_FAIL);
            }
            return jr;
        }
    
        private void processShard(Integer shardId) {
            try {
                logger.info("开始处理分片数据 分片id:{}",shardId);
                long start = System.currentTimeMillis();
                long total = 0;
                Integer lastId = 0;
                List<TaskRecord> taskRecordList = taskRecordManager.findTaskRecordByShard(shardId, lastId, 1000);
                while (!taskRecordList.isEmpty()) {
                    total += taskRecordList.size();
                    processData(taskRecordList);
                    lastId = taskRecordList.get(taskRecordList.size() - 1).getId();
                    taskRecordList = taskRecordManager.findTaskRecordByShard(shardId, lastId, 1000);
                }
                logger.info("处理分片数据结束 分片id:{} total:{} 耗时:{}ms", shardId,total, System.currentTimeMillis() - start);
            } catch (Exception e) {
                logger.error("定时任务处理分片数据失败,分片id:{}", shardId, e);
            }
        }
    
        private void processData(List<TaskRecord> taskRecordList) {
            executorService.submit(() -> {
                if (!CollectionUtils.isEmpty(taskRecordList)) {
                    TaskCheck taskCheck;
                    for (TaskRecord taskRecord : taskRecordList) {
                        taskCheck = new TaskCheck();
                        if(taskRecordService.checkInValid(taskRecord)){
                            logger.info("任务已经失效。record:{}", JSONObject.toJSONString(taskRecord));
                            continue;
                        }
                        taskCheck.setMobile(taskRecord.getMobile());
                        taskCheck.setIds(taskRecord.getTaskCode());
                        taskCheck.setScene(taskRecord.getScene());
                        taskCheck.setUserId(taskRecord.getUserId());
                        taskRecordService.checkTaskJob(taskCheck);
                    }
                }
            });
        }
    
    }
    

    3 部分运行截图: 

    展开全文
  • 1、新增定时任务(新增、修改、删除、查询、启动/暂停)2、新增调度日志(查询、删除) 平台简介 一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适自己的。于是利用空闲休息时间开始自己写一套后台...

    若依管理系统 v1.0.8 已发布,更新日志:

    1、新增定时任务(新增、修改、删除、查询、启动/暂停)
    2、新增调度日志(查询、删除)

    平台简介

    一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适自己的。于是利用空闲休息时间开始自己写一套后台系统。如此有了若依管理系统。她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA。所有前端后台代码封装过后十分精简易上手,出错效率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。

    若依是给刚出生的女儿取的名字 寓意:你若不离不弃,我必生死相依

    部分功能演示

     

     

    展开全文
  • 2 今天任务的完成情况 2 基本功能实现了,但是有些信息还需要转换。 3 遇到了哪些困难 思考了一下会员模块的整体实现。发现社团的管理和ADmin的管理的权限问题,如何正确的进入页面和保留进入页面的信息。 4 ...
    1. 今天做了什么

      1 今天基本完成了所有action简单的功能的实现。

    2 今天任务的完成情况

         2 基本功能实现了,但是有些信息还需要转换。

    3 遇到了哪些困难

        思考了一下会员模块的整体实现。发现社团的管理和ADmin的管理的权限问题,如何正确的进入页面和保留进入页面的信息。

    4 如何解决遇到的困难

      等待整体讨论。

    5 明天的计划

      将说有的管理页面用框架也实现。

    转载于:https://www.cnblogs.com/116913829/archive/2011/03/18/1988020.html

    展开全文
  • 问题描述项目中需要定时同步会员系统司机(会员)数据,为了简化开发,直接使用jdbcTemplate作为数据库连接;项目测试时候一切正常,等到上线后,第二天IT支持反映问题说,司机表无法操作,紧急排查问题后发现是锁表了...
  • 积分体系和会员体系,两个我们经常听到的名词,对于很多没怎么接触的人来说,很容易将这两个体系,当做同一...举个例子来说,我们经常去超市购物的话,你会发现我们每次结账的时候,收银员都会问我们,“有没有会员卡”
  • PPTV免费会员赠送活动

    2019-09-26 20:10:10
    大家都知道WIN7的任务栏是可以把任务固定在上面以方便使用的,这就好比是WIN7中的另一个小桌面,使用频率高、关注度高。今天发现PPTV独创新的营销方式,把营销拓展到这块重要的的用户入口,有兴趣的同学可以体验一下...
  • 大家回想起使用淘宝天猫等APP的使用经历,或者使用三大运营商的的积分兑换礼物时,有没有发现他们有一个共同的特点:那就是我们都是完成某一个官方规定的任务后,我们就能获得一定的积分奖励,并且后续,这些积分...
  • 《hp打印机无法取消打印的文档解决方法(最新整理)》由会员分享,可在线阅读,更多相关《hp打印机无法取消打印的文档解决方法(最新整理)(2页珍藏版)》请在人人文库网上搜索。1、hp 打印机无法取消或删除正在打印的...
  • 工作任务: 把这样的数据,整理出,每个公司投资了几个国家,这个公司在全球总共投资几笔。 每个公司在全球共投资几笔,也就是每个公司有几条记录。这个功能用excel的数据透视表很简单就能做出来(傻瓜版:wps的...
  • 小王经过一段时间学习,慢慢的了解到公司的一些业务架构,发现好几个项目不是LAMP架构就是Nginx+Tomcat,于是小王决定,慢慢的吃透这些架构,先学习LAMP架构,再研究Nginx+Tomcat架构。所以,小王就给自己定一个任务...
  • Synology - Baidu Pan 同步

    千次阅读 2016-12-11 23:35:45
    买了Synology 216II+ 有一段时间了,一直没有折腾,发现装了Cloud Sync, 也没有把百度云上的信息同步下来。... 果断把照片拉到这个目录里,然后网络任务里就多了同步任务——不过没买百度会员,也只能慢慢下载了。
  • 前言 第四天冲刺会议 时间:2019.6.17 地点:宿舍 4.1 今日完成任务情况以及遇到的问题。 4.1.1今日完成任务情况 姚玉婷:管理员功能模块中,收费管理功能...我们将之前完成的部分进行了测试,里面发现了一些小...
  • 有时候发现结 算的数据不对也是由于后台转移造成的,但是票数不会少的. 12. 有时候软件上有票,后台上没票,你可以 点 停止投票 在点 开始投票 一般这样票数就上传了, 要是这样还没上票就关了软件在开吧,还不行就换...
  • 问题原由最近使用quartz写了一个定时任务,这个定时任务主要是给会员增加类似积分的东西,并且要保存积分增加记录,每天凌晨4点钟执行,但是会有些时候会出现很多会员的积分并没有增加,查了一下日志,发现Druid抛出...
  • 2020-10-19

    2020-10-19 15:57:08
    大家回想起使用淘宝天猫等APP的使用经历,或者使用三大运营商的的积分兑换礼物时,有没有发现他们有一个共同的特点:那就是我们都是完成某一个官方规定的任务后,我们就能获得一定的积分奖励,并且后续,这些积分...
  • 1、网站首页版块有:招标城市切换、家装招标信息发布、工装招标信息发布、招标任务信息发布。 2、招标信息发布页面简洁明了,排版很合理,可直接在线发布招标信息。 3、后台包括:地区管理、广告管理、信息管理、...
  • 昨天发现线上试跑期的一个程序挂了,平时都跑的好好的,查了下日志是因为昨天运营跑了一家美妆top级淘品牌店,会员量近千万,一下子就把128G的内存给爆了,当时并行跑了二个任务,没辙先速写一...
  • 来csdn的第一天

    2010-08-19 14:44:00
    昨天在网上搜寻资料的时候,发现了CSDN这个论坛,感觉特别的好,就注册会员了。 刚进CSDN嘛,就带着好奇心转来转去,熟悉了一下。给我的感觉和第一感觉一样,这个论坛很不错,我很喜欢!今天开始完善自己的资料,...
  • 酷爱装网站

    2012-11-09 23:34:58
    1、网站首页版块有:招标城市切换、家装招标信息发布、工装招标信息发布、招标任务信息发布。 2、招标信息发布页面简洁明了,排版很合理,可直接在线发布招标信息。 3、后台包括:地区管理、广告管理、信息管理、...
  • 使用全新的迅雷11,您...本地SVIP10会员,VIP标识和悬浮窗,自动会员加速试用 去右下角推广弹窗、去下载任务文字广告、去头像悬浮广告 去主界面登陆送2T空间按钮、顶部搜索框栏、用户消息按钮 去面板侧边栏按钮:发现.
  • 免费不限速不限存储的网盘推荐

    千次阅读 2020-08-27 11:04:58
    空间:超级会员任务扩容至5T空间,普通会员2T,一般用户大多在1T~2T之间,分享文件没有传输流量与下载次数限制,只限速。 上传:普通用户的速度就不说了,开通SVIP后上传速度为4.5MB/s。 下载:速度约...
  • 任务理解 张三,护肤品及彩妆类卖家,几经打拼,信用积累到皇冠,但也累得半死,每日深陷护肤品行业的红海鏖战之中。感觉现在淘宝上的竞争越来越激烈,爆款可以带来销量,却带不来多少利润。促销、聚划算之类的活动...
  • 3、后台包括:地区管理、广告管理、信息管理、个人会员管理、公司会员管理等。网站所有内容后台直接操作。4、更多功能,还需要自己去发现。经测试,程序无任何问题。网站后台管理:地址:域名/admin/用户名:admin...
  • 1、首先就是下载问题由于在官网下载很慢直接在百度上搜索发现有0积分的csdn分享直接做了一个任务获得了百度网盘的链接这里也直接分享出来 链接:https://pan.baidu.com/s/1gfZY3eV 密码:zfc3 官网太慢了 ,网盘会员...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 126
精华内容 50
关键字:

发现会员任务