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

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

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

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

Q&A

解決済

2回答

2016閲覧

jlineのpromptが非同期でメッセージを出力すると動作がおかしくなる

Tron

総合スコア27

Java

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

0グッド

0クリップ

投稿2015/08/09 13:26

編集2015/08/10 02:38

jlineのpromptが非同期でメッセージを出力すると動作がおかしくなります
具体的には、ConsoleReader#setPrompt(String)で指定している文字の後に非同期で出力したメッセージが表示されてしまいます。
どうすればいいでしょうか?
同期実行されている場合はこのようにはなりません。
イメージ説明

Java

1 public static void main(String args[]) { 2 try { 3 final ConsoleReader reader = new ConsoleReader(); 4 reader.setExpandEvents(false); 5 6 while (true) { 7 String line = reader.readLine(">"); 8 if (line != null) { 9 if (line.split(" ")[0].equalsIgnoreCase("copy")) { 10 System.out.println("Start Copy Thread"); 11 Thread thread = new Thread(new Runnable() { 12 @Override 13 public void run() { 14 // Dummy 15 try { 16 Thread.sleep(1000); 17 } catch (InterruptedException e) { 18 e.printStackTrace(); 19 } 20 System.out.println("End Copy Thread"); 21 } 22 }); 23 thread.start(); 24 } 25 } 26 } 27 } catch (Throwable t) { 28 t.printStackTrace(); 29 } 30 }

期待する動作
下記のようにプロンプト部分「>」に出力された文字がかぶらないようにしたいです。
常に一番下の行にプロンプト部分「>」が来るようにしたいです。

copy

Start Copy Thread
End Copy Thread

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

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

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

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

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

eripong

2015/08/09 13:42

書いたとおりに動いているように思います。どの様な動作を期待されていますか?
Tron

2015/08/09 14:10

>hoge hoge hoge とならないで hoge hoge hoge > となってほしいのです。
guest

回答2

0

SwingやJavaFXのようにUIの書き換え処理をキューに貯め、キューに変更があった時にコンソールに出力するのはどうでしょうか?

投稿2015/08/10 01:56

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

eripong

2015/08/10 02:04

そうですね。 何らかの方法で同期する必要があると思います。
退会済みユーザー

退会済みユーザー

2015/08/10 03:21

UIの書き換え処理は同期的に扱っていても、copy処理などの呼び出し側の処理をブロックしないように実装できれば、Copy処理からみれば非同期です。がんばってください。
guest

0

ベストアンサー

プロンプトを出力するスレッドと、hogeと出力するスレッドを別にしているので、
プロンプトとhogeがどの様な順で出力されるかは、決まらないです。

それが、非同期ということと思うのですが、
何のためにその様にしたいのでしょうか?

サンプルコード

少しは近い状態になったと思います。
copyが完了した瞬間に出力、といいうのはJLineに手を入れないと難しそうなので、
copyが完了した後、Enterした際に表示する、という形にしています。

lang

1 public static void main(String args[]) { 2 try { 3 final StringBuffer buff = new StringBuffer(); 4 5 final ConsoleReader reader = new ConsoleReader(); 6 while (true) { 7 String line = reader.readLine(">"); 8 synchronized (buff) { 9 if (buff.length() > 0) { 10 reader.resetPromptLine(buff.toString() + "\n", "", -1); 11 buff.delete(0, buff.length()); 12 } 13 } 14 if (line != null) { 15 if (line.split(" ")[0].equalsIgnoreCase("copy")) { 16 System.out.println("Start Copy Thread"); 17 Thread thread = new Thread(new Runnable() { 18 @Override 19 public void run() { 20 // Dummy 21 try { 22 Thread.sleep(1000); 23 } catch (InterruptedException e) { 24 e.printStackTrace(); 25 } 26 27 buff.append("End Copy Thread"); 28 } 29 }); 30 thread.start(); 31 } 32 } 33 34 } 35 } catch (Throwable t) { 36 t.printStackTrace(); 37 } 38 }

実行結果:

>copy Start Copy Thread > (ここでEnter入力) End Copy Thread >

投稿2015/08/09 14:29

編集2015/08/10 07:37
eripong

総合スコア1546

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

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

eripong

2015/08/09 14:34

すみません。 ちょっと書きかけで投稿してしまったので、また後で追記します。
Tron

2015/08/09 14:50 編集

>何のためにその様にしたいのでしょうか? 簡単な対話型プログラムを作ろうとしています 例えば >copy A to B と打ったらコピースレッドを起動してファイルコピーを行う感じです コピーが終了したときにコピースレッドからSystem.out.println()をしたいのですが そうするとプロンプトの'>'がずれてしまうのです。 また、コピー中も他の操作を行いたいのでThread#join()で待つことはできません。
eripong

2015/08/10 00:57

シェルのバックグラウンド実行のイメージですね。 コピーが終わったら コピーが終わりました。 > のように、メッセージを出して、プロンプトを出したい、 ということでよいでしょうか? すぐにはできなそうなので、少し考えてみます。
Tron

2015/08/10 01:26

ありがとうございます。 こちらでも色々試してみたのですがどうやってもずれてしまって... また、コマンド入力中に非同期メッセージが出力されたときもコマンドとメッセージがかぶってしまうことがわかりました
eripong

2015/08/10 06:52 編集

試してみましたが、これでどうでしょうか? キューをきちんと使わず、StringBufferでさぼっていますが、 実際にはキューを使った方が良いかとは思います。
Tron

2015/08/10 07:19

実行してみましたが、何も入力できません...
eripong

2015/08/10 07:22

おっと、そうですか。ちょっと確認してみます。
Tron

2015/08/10 07:23

結局のところ、表示が崩れてしまう根本的な原因はreader.readLineで待機しているからなのですかね?
eripong

2015/08/10 07:25

このコードをコピペしても、こちらだと動きます。 mainメソッドの最後の}が抜けてましたが、そこではないですよね?
eripong

2015/08/10 07:31

何を持って崩れるというかによりますが、元々の処理では、mainスレッドでプロンプトを出力して、Timerスレッドで結果を出力しているので、プロンプトと結果が混ざっていました。 出力を1スレッドで行うようにしないと、混ざる現象は解消できません。 そのため、今回はreader.readLineの後で、 出力メッセージがあればmainスレッド側で出力する様にしました。 これにより、プロンプト出力と、結果出力が同じmainスレッドからになり、 混ざることはなくなったはずです。
eripong

2015/08/10 07:32

何も入力できない、というのはどういう状態ですか? 最初のプロンプトだけ出ている状態でしょうか?
eripong

2015/08/10 07:38 編集

こちらで使用しているのは、git://github.com/jline/jline2.gitから取得したソースでビルドしたJLine 2.13と、Java 8u45ですが、バージョンはあっているでしょうか? それから、Java8でなければStringBuffer buffがfinalである必要があるので、 付け加えてみました。
Tron

2015/08/10 08:08

実行できました。 Enterキーを押すことにメッセージの出力を確認できましたが、やはり私が期待しているような動作をさせることは不可能なのでしょうか?
eripong

2015/08/10 08:15

不可能ではないですが、難しいと思います。 Tronさんが期待している動作をするには、reader.readLineで待機している間に、 copyを行ったスレッドで処理が完了した場合、readLineを中断してメッセージの出力を行う必要があり、それを実現するためには、JLineに手を入れなければならないと思います。
Tron

2015/08/10 10:08

ありがとうございました。
Tron

2015/08/10 10:09 編集

# 消去
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問