【无层级消息树】无层级消息树构建(并发线程安全)

 背景

        常规消息树或菜单栏可以使用递归进行构建,但最近遇见一个需求,需要提供一个留言板的功能,不使用懒加载,前端页面需要一次性展示所有留言,并且支持新增留言和删除留言等功能;

为了提升后端API的高可用性能,所以针对此需求进行了一些简单的思考,并以此做一个记录;

具体实现

/**
 * 无 限 层 级 树
 * @author F-QiXian
 * @date 2022/6/14 15:20
 */
@Data
@NoArgsConstructor
public class InfiniteMessageTree {

    /**
     * 初始化无限层级树
     * @param list 消息列表
     */
    public InfiniteMessageTree(List<MessageTreeNode> list){
        this.init(list);
    }

    /**
     * 消息树: 使用 CopyOnWriteArrayList 避免并发数据更新出现线程安全问题
     */
    private List<MessageTreeNode> listTree = new CopyOnWriteArrayList<>();

    /**
     * 节点映射:通过映射对节点增删操作的时间复杂度为O(1), 使用 ConcurrentHashMap 避免并发数据更新出现线程安全问题
     */
    private Map<String, List<MessageTreeNode>> nodeMapping  = new ConcurrentHashMap<>();


    /**
     * 初始化无限层级树
     * @param list 列表数据
     * @return InfiniteMessageTree
     */
    public void init(List<MessageTreeNode> list) {
        // 通过父节点ID排序,使用降序插入的方式避免tree节点翻转
        list.stream().sorted(Comparator.comparingLong(MessageTreeNode::getParentId)).forEach(this::findParentAdd);
    }

    /**
     * 根据父级ID寻找节点子集插入
     * @param node 目标节点
     * @return 添加成功或失败
     */
    public boolean findParentAdd(MessageTreeNode node) {
        // 父级ID的 Key
        String key = node.getParentId().toString();
        // 设置子集映射
        nodeMapping.put(node.getId().toString(), node.getChildren());
        // 通过缓存插入记录或直接插入为头节点
        return (nodeMapping.containsKey(key)) ? nodeMapping.get(key).add(node) : listTree.add(node);
    }

    /**
     * 树节点
     * @author F-QiXian
     * @date 2022/6/14 15:15
     */
    @Data
    public static class MessageTreeNode {

        /**
         * 节点唯一ID
         */
        private Long id;

        /**
         * 父节点ID
         */
        private Long parentId;

        /**
         * 节点内容
         */
        private String content;

        /**
         * 子节点
         */
        private List<MessageTreeNode> children = new CopyOnWriteArrayList<>();

    }

}

 一些思考

        这个消息树可以注册为一个单例的bean,系统在初始化的时候进行构建,当用户发生了更新行为直接进行异步API调用(因为是单例的bean所以使用 CopyOnWriteArrayList 和 ConcurrentHashMap 来保证并发修改的线程安全问题),当用户发起请求留言,此时需要进行数据持久化并返回主键的id,前端需要进行树内容的更新,因为可能存在其他用户修改留言信息,所以前端页面不能直接更新jsongArray data , 需要再次刷新;

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值