3

私はGoogle Gauvaバージョン11.0.1を使用しており、次のコードがあります:

ImmutableList.copyOf(items);

items は ConcurrentLinkedQueue です。ときどき次のエラーが表示されます。

java.lang.ArrayIndexOutOfBoundsException: 10
at java.util.AbstractCollection.toArray(AbstractCollection.java:126)
at com.google.common.collect.ImmutableList.copyFromCollection(ImmutableList.java:278)
at com.google.common.collect.ImmutableList.copyOf(ImmutableList.java:247)
at com.google.common.collect.ImmutableList.copyOf(ImmutableList.java:217)

問題が完全にグアバライブラリ内にあることを考えると、その理由を知っている人はいますか?

以下の正解に基づいて更新

wolfcastle の助けを借りて、アプリケーションの外部で問題を分離して再現することができました。

final int itemsToPut = 30000;

final ConcurrentLinkedQueue<Integer> items = new ConcurrentLinkedQueue<Integer>();
new Thread(new Runnable() {
    public void run() {
       for (int i = 0; i < itemsToPut; i++) {
           items.add(i);
           }
    }
}, "putter-thread").start();
final Iterable<String> transformed = Collections2.transform(items, new Function<Integer, String>() {
    public String apply(Integer integer) {
        return "foo-" + integer;
    }
});
ImmutableList.copyOf(transformed);

これを実行すると、毎回次が生成されます。

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 21480
    at java.util.AbstractCollection.toArray(AbstractCollection.java:126)
    at com.google.common.collect.ImmutableList.copyFromCollection(ImmutableList.java:278)
    at com.google.common.collect.ImmutableList.copyOf(ImmutableList.java:247)
    at com.google.common.collect.ImmutableList.copyOf(ImmutableList.java:217)

私のアプリケーションで解決するために、いくつかのオプションを見つけました。

Collections2 からの移行

Collections2.transform から Iterables.transform に切り替えると、問題はなくなります。

Java 1.5 からの移行

これは私の状況では不可能でしたが、Java 1.6 と Java 1.7 で試してみたところ、問題は解決しました。これは、AbstractCollection.toArray() の実装が 1.5 から変更されたためだと思われます。

1.5

public Object[] toArray() {
    Object[] result = new Object[size()];
    Iterator<E> e = iterator();
    for (int i=0; e.hasNext(); i++)
        result[i] = e.next();
    return result;
}

1.6

public Object[] toArray() {
    // Estimate size of array; be prepared to see more or fewer elements
    Object[] r = new Object[size()];
        Iterator<E> it = iterator();
    for (int i = 0; i < r.length; i++) {
        if (! it.hasNext()) // fewer elements than expected
        return Arrays.copyOf(r, i);
        r[i] = it.next();
    }
    return it.hasNext() ? finishToArray(r, it) : r;
}

最初に ConcurrentLinkedQueue をコピーする

スレッドセーフでないコレクションで変換を実行することは、明らかに理想からはほど遠いものです。何らかの理由で Collections2.transform を使用しなければならない場合は、最初にアイテム コレクションのコピーを取得することで問題を解決できます。

4

2 に答える 2

6

コレクションの toArray() メソッドに問題があるようです。ConcurrentLinkedQueue を使用していると言いますが、スタック トレースはAbstractCollection.toArray. java.util.ConcurrentLinkedQueue独自の toArray 実装があるため、これは怪しいようです。

実際に使用しているコレクションは何ですか? コレクションではないと思いImmutableListます。

于 2013-08-22T15:58:52.590 に答える
1

の実行中にリストのサイズが変化する可能性はありcopyOf()ますか?

メソッドの開始時にサイズをチェックしているが、ConcurrentLinkedQueueサイズが大きくなると、ArrayIndexOutOfBoundsException.

于 2013-08-22T15:55:26.437 に答える