You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于自定义类WiSeConSyncItem,移除子列表重复项后合并至主列表

这是个典型的多线程场景下的列表去重合并需求,我来给你拆解实现思路和具体代码方案:

核心需求分析

你需要解决两个关键问题:

  • 高效判断子列表中的元素是否已存在于mainItems(依据processId唯一标识)
  • 保证多线程操作mainItems时的线程安全(毕竟mainItems同时被API循环任务和定时器修改)
具体实现方案

1. 基础去重方法(单线程场景)

如果你的场景暂时没有多线程并发修改的问题,基础版的去重逻辑就足够高效:

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class SyncItemHandler {

    /**
     * 将子列表去重后合并到主列表
     * @param mainItems 主列表
     * @param subItems 需要合并的子列表
     */
    public void mergeUniqueItems(List<WiSeConSyncItem> mainItems, List<WiSeConSyncItem> subItems) {
        // 提取主列表中已有的processId集合,用于快速查重
        Set<Integer> existingIds = mainItems.stream()
                .map(item -> item.processId)
                .collect(Collectors.toSet());

        // 过滤子列表,只保留主列表中没有的元素
        List<WiSeConSyncItem> uniqueSubItems = subItems.stream()
                .filter(item -> !existingIds.contains(item.processId))
                .collect(Collectors.toList());

        // 将去重后的元素添加到主列表
        mainItems.addAll(uniqueSubItems);
    }
}

2. 线程安全版本(多线程场景必用)

因为你提到mainItems同时被API循环(耗时操作)和定时器修改,而ArrayList本身不是线程安全的,直接操作会触发ConcurrentModificationException或者数据不一致问题,这里提供两种常用的线程安全方案:

方案A:同步块+普通ArrayList

用统一的锁对象包裹所有操作mainItems的代码,保证同一时间只有一个线程修改或读取列表:

public class SyncItemHandler {
    // 全局锁对象,所有操作mainItems的方法都要使用这个锁
    private final Object listLock = new Object();

    public void mergeUniqueItemsThreadSafe(List<WiSeConSyncItem> mainItems, List<WiSeConSyncItem> subItems) {
        synchronized (listLock) {
            Set<Integer> existingIds = mainItems.stream()
                    .map(item -> item.processId)
                    .collect(Collectors.toSet());

            List<WiSeConSyncItem> uniqueSubItems = subItems.stream()
                    .filter(item -> !existingIds.contains(item.processId))
                    .collect(Collectors.toList());

            mainItems.addAll(uniqueSubItems);
        }
    }

    // 定时器添加元素的方法也要用同一个锁
    public void addItemByTimer(List<WiSeConSyncItem> mainItems, WiSeConSyncItem newItem) {
        synchronized (listLock) {
            mainItems.add(newItem);
        }
    }
}

方案B:使用CopyOnWriteArrayList线程安全集合

适合读多写少的场景,底层通过复制数组实现线程安全,读操作无锁:

import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

public class SyncItemHandler {
    // 初始化mainItems为线程安全的CopyOnWriteArrayList
    private List<WiSeConSyncItem> mainItems = new CopyOnWriteArrayList<>();

    public void mergeUniqueItems(List<WiSeConSyncItem> subItems) {
        // CopyOnWriteArrayList的迭代是线程安全的,不会抛出并发修改异常
        Set<Integer> existingIds = mainItems.stream()
                .map(item -> item.processId)
                .collect(Collectors.toSet());

        List<WiSeConSyncItem> uniqueSubItems = subItems.stream()
                .filter(item -> !existingIds.contains(item.processId))
                .collect(Collectors.toList());

        // addAll操作自带线程安全保障
        mainItems.addAll(uniqueSubItems);
    }
}
性能优化建议

如果mainItems数据量很大,每次遍历提取processId会有开销,可以维护一个单独的线程安全集合来记录已存在的processId,避免重复遍历主列表:

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class SyncItemHandler {
    private final Object lock = new Object();
    private List<WiSeConSyncItem> mainItems = Collections.synchronizedList(new ArrayList<>());
    private Set<Integer> existingProcessIds = Collections.synchronizedSet(new HashSet<>());

    public void mergeUniqueItems(List<WiSeConSyncItem> subItems) {
        synchronized (lock) {
            List<WiSeConSyncItem> uniqueSubItems = subItems.stream()
                    .filter(item -> !existingProcessIds.contains(item.processId))
                    .collect(Collectors.toList());
            
            mainItems.addAll(uniqueSubItems);
            // 同步更新processId集合
            uniqueSubItems.forEach(item -> existingProcessIds.add(item.processId));
        }
    }

    public void addItem(WiSeConSyncItem item) {
        synchronized (lock) {
            mainItems.add(item);
            existingProcessIds.add(item.processId);
        }
    }
}

内容的提问来源于stack exchange,提问作者noobEinstien

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:18:21