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

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

ただいまの
回答率

87.48%

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

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 2,501

score 1518

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));

    }

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

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

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

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

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

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

class Foo {
  public Object lock = new Object();

  @Override
  public toString() {
    synchronized (lock) {
      return "foo";
    }
  }
}

プログラム実行途中で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 20:29 編集

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

    キャンセル

  • 2018/04/01 21:31 編集

    詳しく見てないですが、bubble_downの論理で入力データに比較結果が同じものが複数含まれている場合に計算が停止しないように思えます。こういうケースは一段回ずつデバッグすることをお奨めします。

    まずはこのメソッドの処理対象にしている場所(インデックス)デバッグプリントを入れ、無限ループしているようなのでループの先頭ででもbreakpointを設定し、ループ毎にデバッグプリントの結果を確かめるあたりからやるといいんじゃないでしょうか。

    ---
    回答に書いた入力例:AaAだと無限ループすると思います。

    キャンセル

  • 2018/04/03 00:26

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

    キャンセル

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

  • ただいまの回答率 87.48%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る