避免两者的java惯用方法:内存泄漏和concurrentmodificationexception

tktrz96b  于 2021-06-29  发布在  Java
关注(0)|答案(0)|浏览(226)

我编写了一个递归算法,基本上如下所示。我用的是 Map<Integer, Long> 作为一个穷人的袋子/多套。为了避免 ConcurrentModificationException 我从不从Map上删除/添加键。它运行良好,而且 0 在此上下文中,不删除事件并不重要。
ps:我知道它不能扩展,它只是一种有趣的/通用的方式来解决代码日1第1部分和第2部分的出现。

Optional<Integer> solve(final Map<Integer, Long> intOccurrences, final int sum, final int addendsCount) {
    if (addendsCount < 1) return Optional.empty();
    if (addendsCount == 1) {
        return intOccurrences.getOrDefault(sum, 0L) > 0 ? Optional.of(sum) : Optional.empty();
    }

    for (val entry : intOccurrences.entrySet()) {
        if (entry.getValue() < 1) continue;
        val left = entry.getKey();
        val delta = sum - left;

        changeCountOf(intOccurrences, left, -1);

        val result = solve(intOccurrences, delta, addendsCount - 1);

        if (result.isPresent()) {
            return Optional.of(left * result.get());
        }

        changeCountOf(intOccurrences, left, 1);
    }

    return Optional.empty();

}

因为我已经好几年没有编写java了,所以我决定通过实现一个 IntBag . 我已经实施了 IntBag 用一个 Map<Integer, Count> 实现的背景图 Iterable<Occurrence> . 自定义迭代器由Map的 entrySet 迭代器和跳过 0 事件。
一切正常,但我现在 IntBag 实现与递归回溯算法配合得很好,它还会因为 0 事件永远不会被清除。

问题

有没有一种替代的方法来实现一个包,它不会遭受这种内存泄漏问题,同时避免 CurrentModificationException (这不包括复制整个包)?
如果我当前的实现有意义的话,有什么合适的方法来清理条目?例如,我想过在某个阈值之后运行gc进程,但我不确定哪个阈值有意义,等等。
我曾想过在迭代过程中标记要删除的条目,然后在所有迭代完成后进行清理,但我认为如果我实现了,就没有办法保证所有迭代都完成了 Iterable . 如果我只执行 forEach 但是,在最外层 forEach 退出(在迭代过程中仍然需要忽略0次出现的值)。
以上这些都不能解决递归迭代时添加新值的问题。我想不出一个办法,除了复制整个包现在工作?希望在迭代时添加项不是很常见,我猜。。。
这个 IntBag 实现当前看起来是这样的(由于没有必要,所以没有实现添加/删除):

final class IntBag implements Iterable<IntBag.Occurrence> {
    private final Map<Integer, Count> occurrenceMap;

    private IntBag(final Map<Integer, Count> occurrenceMap) {
        this.occurrenceMap = occurrenceMap;
    }

    boolean contains(final int value) {
        return !occurrenceMap.getOrDefault(value, Count.ZERO).isZero();
    }

    @Override
    public Iterator<Occurrence> iterator() {
        return new IntBag.BagIterator(occurrenceMap.entrySet().iterator());
    }

    static IntBag of(final List<Integer> values) {
        return new IntBag(countInts(values));
    }

    private static Map<Integer, Count> countInts(final List<Integer> values) {
        return values.stream().collect(groupingBy(Function.identity(), reducing(Count.ZERO, e -> Count.ONE, Count::merge)));
    }

    private static final class BagIterator implements Iterator<Occurrence> {
        private final Iterator<Entry<Integer, Count>> entryIterator;
        private Entry<Integer, Count> nextEntry;

        BagIterator(@NonNull final Iterator<Entry<Integer, Count>> entryIterator) {
            this.entryIterator = entryIterator;
            initNext();
        }

        @Override
        public boolean hasNext() {
            return nextEntry != null;
        }

        @Override
        public Occurrence next() {
            if (!hasNext()) throw new NoSuchElementException();
            val currentEntry = nextEntry;
            initNext();
            return new Occurrence(currentEntry);
        }

        private void initNext() {
            while(entryIterator.hasNext()) {
                val maybeNext = entryIterator.next();
                if (maybeNext.getValue().isZero()) continue;
                nextEntry = maybeNext;
                return;
            }

            nextEntry = null;
        }
    }

    @RequiredArgsConstructor
    static final class Occurrence {
        private final Map.Entry<Integer, Count> entry;

        int value() {
            return entry.getKey();
        }

        long count() {
            return entry.getValue().value();
        }

        void merge(final long modifier) {
            entry.setValue(entry.getValue().merge(modifier));
        }
    }

    private static final class Count {
        private final long value;

        private Count(final long value) {
            this.value = Math.max(0L, value);
        }

        long value() {
            return value;
        }

        boolean isZero() {
            return value == 0L;
        }

        Count merge(@NonNull final Count modifier) {
            return merge(modifier.value());
        }

        Count merge(final long modifier) {
            return new Count(value + modifier);
        }

        static final Count ZERO = Count.of(0L);
        static final Count ONE = Count.of(1L);
        static Count of(final long value) {
            return new Count(value);
        }
    }
}

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题