質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Eclipse

Eclipseは、IBM社で開発された統合開発環境のひとつです。2001年11月にオープンソース化されました。 たくさんのプラグインがあり自由に機能を追加をすることができるため、開発ツールにおける共通プラットフォームとして位置づけられています。 Eclipse自体は、Javaで実装されています。

Q&A

解決済

1回答

4473閲覧

Eclipseで"toString() unavailable - No suspended threads"エラーが表示される

Udomomo

総合スコア1524

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Eclipse

Eclipseは、IBM社で開発された統合開発環境のひとつです。2001年11月にオープンソース化されました。 たくさんのプラグインがあり自由に機能を追加をすることができるため、開発ツールにおける共通プラットフォームとして位置づけられています。 Eclipse自体は、Javaで実装されています。

0グッド

0クリップ

投稿2018/04/01 04:42

Eclipse4.7.3を使用しています。
Javaでヒープソートアルゴリズムのコードを書き、実行させたのですが、いくら待ってもコードが停止しませんでした。

デバッグモードで調べたところ、executeHeapSortメソッドの中でtoString()を呼び出した箇所で、toString() unavailable - No suspended threadsというメッセージが表示されました。
マルチスレッドで走らせる実装にはしていないのですが、このエラーはどのような原因で起こっているのでしょうか?

import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Scanner; class HeapManager { List<String> heapArray = new ArrayList<String>(); List<String> resultArray = new ArrayList<String>(); public String executeHeapSort(String target) { List<String> targetArray = new ArrayList<String>(Arrays.asList(target.split(""))); insert(targetArray); extract_min(); return toString(); } public void insert(List<String> targetArray) { for (String s : targetArray) { heapArray.add(s); int added_index = heapArray.size() - 1; bubble_up(added_index); } } public void extract_min() { while (heapArray.size() > 0) { int size = heapArray.size(); resultArray.add(heapArray.get(0)); swapHeapValue(0, size - 1); heapArray.remove(size - 1); bubble_down(0); } } public void bubble_up(int index) { while (index > 0) { int parent_index = Math.floorDiv(index + 1, 2) - 1; if (hasSmallerValue(index, parent_index)) { swapHeapValue(index, parent_index); index = parent_index; } else return; } } public void bubble_down(int index) { while (true) { int left_child_index = index * 2 + 1; int right_child_index = left_child_index + 1; int min_child_index; if (left_child_index > heapArray.size() - 1) { break; } else if (right_child_index > heapArray.size() - 1) { min_child_index = left_child_index; } else { if (hasSmallerValue(left_child_index, right_child_index)) { min_child_index = left_child_index; } else min_child_index = right_child_index; } if (hasSmallerValue(min_child_index, index)) { swapHeapValue(min_child_index, index); index = min_child_index; } } } public boolean hasSmallerValue(int i, int j) { if (heapArray.get(i).compareToIgnoreCase(heapArray.get(j)) < 0) { return true; } else if (heapArray.get(i).compareToIgnoreCase(heapArray.get(j)) == 0) { if (heapArray.get(i).compareTo(heapArray.get(j)) < 0) { return true; } } return false; } public void swapHeapValue(int i, int j) { String temp = heapArray.get(i); heapArray.set(i, heapArray.get(j)); heapArray.set(j, temp); } @Override public String toString() { StringBuilder buf = new StringBuilder(); for (String str: resultArray) { buf.append(str); } return buf.toString(); } } public class HeapSort { public static void main(String[] args) { Scanner stdIn = new Scanner(System.in); String target = stdIn.next(); stdIn.close(); HeapManager heap = new HeapManager(); System.out.println(heap.executeHeapSort(target)); } }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

このエラーはどのような原因で起こっているのでしょうか?

推測ですが、あなたはこのように操作したのではないでしょうか?

(A) デバッグ実行開始
(B) Eclipseのconsoleからデータを入力
例えばAaAのようなデータを入力したんだろうと思います。
(C) プログラムが停止しないのでpauseボタンを押した
(D) mainスレッドのスタックトレース上でbubble_down(int)メソッドなどを選択
(E) 変数ウィンドウのところのthis(即ちHeapManagerのインスタンス)の値を見ようとしたらそのメッセージが表示されていた

Eclipseや他のJava IDEでは参照型のインスタンスの値をデバッガーで参照した際にtoString()を呼び出してその結果を表示してくれたりしますが、それにはデバッグ中のプログラムのtoString()をデバッガーが自動的に呼び出して結果を得ています。しかし、デバッグ対象のプログラムがプログラムの途中で中断しているようなケースの場合、その状態で下手にtoString()を呼び出してしまうと結果が予測できない場合があります。

例えばtoStringの実装が以下のようなものだったと想像してみてください。

java

1class Foo { 2 public Object lock = new Object(); 3 4 @Override 5 public toString() { 6 synchronized (lock) { 7 return "foo"; 8 } 9 } 10}

プログラム実行途中でpauseした場合、もしかしたらFoo#lockオブジェクトは他のスレッドがモニターを保持しているかも知れませんね?そんな状況でデバッガーがFoo#toStringを呼び出してしまうとtoStringが結果を返すことができず、デバッガー自体がフリーズしてしまうかも知れません。

こういうわけでEclipseはインスタンスの値を表示する際にtoStringを用いるかどうかをある基準で判断しているのだろうと思います。その基準に抵触するケースに「toString() unavailable - No suspended threads」があるんじゃないでしょうか?
ちなみに自分は4.7.2ですが、Java>Debug>Detail FormatterでHeapManagerの詳細表示をtoStringでしてねって指定すると、「Detail formatter:Thread must be suspended by step or breakpoint to perform method invocation」と出てました。メッセージの詳細は違いますが、Eclipseが言わんとしていることは同様のことだと思います。

こういう場合、ステップ実行したりどこかにbreakpointを設定してそこまで実行を継続するなりすればtoStringの結果が表示されるようになったりします。

マルチスレッドで走らせる実装にはしていない

Javaのアプリケーションが特に意識してマルチスレッドを使おうとしていなくてもJavaランタイム自体が最初から複数のスレッドで動いています。それゆえEclipseなどのデバッガーは「単純なアプリケーションならスレッドは一つしかない」というような仮定はできないんだろうと思います。

投稿2018/04/01 09:15

KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Udomomo

2018/04/01 11:29 編集

ありがとうございます。確かにそのような操作をしていました。 最初に走らせたときにコードが停止しなかった理由がまだよくわかっていないのですが、そちらの環境でも停止しなかったでしょうか?
KSwordOfHaste

2018/04/01 12:32 編集

詳しく見てないですが、bubble_downの論理で入力データに比較結果が同じものが複数含まれている場合に計算が停止しないように思えます。こういうケースは一段回ずつデバッグすることをお奨めします。 まずはこのメソッドの処理対象にしている場所(インデックス)デバッグプリントを入れ、無限ループしているようなのでループの先頭ででもbreakpointを設定し、ループ毎にデバッグプリントの結果を確かめるあたりからやるといいんじゃないでしょうか。 --- 回答に書いた入力例:AaAだと無限ループすると思います。
Udomomo

2018/04/02 15:26

bubble_down内のwhileループに`break`処理を入れるのを忘れていました。もっと細かくデバッグすればよかったです。 コードは正しい値を出力して終了するようになりました。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問