再帰的な ConcurrentHashMap.computeIfAbsent() の呼び出しが終了しない。バグ?それとも「機能」?
質問
少し前のことですが
フィボナッチ数を再帰的に計算するJava 8の関数的な方法についてブログで書きました。
を使用した
ConcurrentHashMap
キャッシュと、新しい便利な
computeIfAbsent()
メソッドを追加しました。
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class Test {
static Map<Integer, Integer> cache = new ConcurrentHashMap<>();
public static void main(String[] args) {
System.out.println(
"f(" + 8 + ") = " + fibonacci(8));
}
static int fibonacci(int i) {
if (i == 0)
return i;
if (i == 1)
return 1;
return cache.computeIfAbsent(i, (key) -> {
System.out.println(
"Slow calculation of " + key);
return fibonacci(i - 2) + fibonacci(i - 1);
});
}
}
私が選んだのは
ConcurrentHashMap
を選んだのは、この例をさらに洗練させるために並列処理を導入しようと考えていたからです(結局導入しませんでしたが)。
では
8
から
25
に変更し、何が起こるか観察してください。
System.out.println(
"f(" + 25 + ") = " + fibonacci(25));
プログラムは決して止まりません。メソッドの内部ではループがあり、それが永遠に続くだけです。
for (Node<K,V>[] tab = table;;) {
// ...
}
使っています。
C:\Users\Lukas>java -version
java version "1.8.0_40-ea"
Java(TM) SE Runtime Environment (build 1.8.0_40-ea-b23)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)
そのブログ記事の読者である Matthias 氏も問題を確認しました (彼は実際にそれを見つけました)。 .
これは奇妙なことです。私は次の2つのうちどれかを期待していたのですが。
- それは動作します
-
を投げます。
ConcurrentModificationException
でも、決して止まらないだけ?それは危険なように思えます。バグなのでしょうか?それとも、私が何かの契約を誤解していたのでしょうか?
どのように解決するのですか?
これは JDK-8062841 .
での 2011年提案 , コードレビューの際にこの問題を確認しました。JavaDocが更新され、一時的な修正が追加されました。パフォーマンス上の問題から、さらなる書き換えで削除されました。
での 2014 年の議論 で、私たちはより良い検出と失敗の方法を探りました。なお、低レベルの変更を検討するために、議論の一部はオフラインで私的な電子メールに移行しました。すべてのケースをカバーできるわけではありませんが、一般的なケースはライブロックしません。これらの の修正 はDougのリポジトリにありますが、JDKのリリースには至っていません。
関連
-
Springの設定でxsdファイルのバージョン番号を設定しない方が良い理由
-
Javaクラスが "Error occurred during initialization of boot layer "というエラーで実行される。
-
強制型変換について
-
Javaがリソースリークに遭遇した:'input'が閉じない 解決方法
-
[解決済み] Java で、あるコンストラクタを別のコンストラクタから呼び出すにはどうすればよいですか?
-
[解決済み] テールコール最適化とは何ですか?
-
[解決済み] Androidで遅延後にメソッドを呼び出す方法
-
[解決済み] IntelliJ: ワイルドカード・インポートを使用しない
-
[解決済み] Androidでインターネット接続を確認するには?InetAddressがタイムアウトしない
-
[解決済み] 再帰的関数の複雑さの決定(Big O記法)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Springの設定でxsdファイルのバージョン番号を設定しない方が良い理由
-
メモ帳でJavaプログラムをコンパイルして実行すると、Could not find or load main class ...というエラーが表示される。解決方法
-
無効なメソッド宣言
-
FindBugの使用概要
-
API の戻り値を処理するために ResponseEntity を使用する
-
Javaがリソースリークに遭遇した:'input'が閉じない 解決方法
-
Web Project JavaでPropertiesファイルを読み込むと、「指定されたファイルがシステムで見つかりません」というソリューションが表示されます。
-
org.xml.sax.SAXParseExceptionのエラー解決方法
-
linux ant Resolve error: main class not found or couldn't be loaded org.apache.tools.ant.launcher.
-
[解決済み] 新しい関数computeIfAbsentの使い方を教えてください。