- - PR -
asyncExec(Runnable)でwaitを使用すると、「current thread not owner」となってしまう
1
投稿者 | 投稿内容 |
---|---|
|
投稿日時: 2006-09-16 10:22
お世話になっております。
SWTで時間に応じた処理が出来るプログラムを作成しておるのですが、標題のような問題が発生してしまいます。 具体的なプログラムとしては、 import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Display; public class TC_tes { private Shell sShell = null; public static void main(String[] args) { Display display = Display.getDefault(); TC_tes thisClass = new TC_tes(); thisClass.createSShell(); thisClass.sShell.open(); while (!thisClass.sShell.isDisposed()) { if (!display.readAndDispatch()) display.asyncExec(thisClass.new Test()); display.sleep(); } display.dispose(); } private void createSShell() { sShell = new Shell(); sShell.setText("Shell"); sShell.setSize(new Point(300, 200)); } public class Test implements Runnable{ int a = 0; public void run() { try { while(!sShell.isDisposed()){ System.out.println(a); a++; wait(1000); } } catch (InterruptedException e) { e.printStackTrace(); } } } } また、エラー内容としては、 org.eclipse.swt.SWTException: Failed to execute runnable (java.lang.IllegalMonitorStateException: current thread not owner) at org.eclipse.swt.SWT.error(SWT.java:3374) at org.eclipse.swt.SWT.error(SWT.java:3297) at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:126) at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3325) at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:2971) at execute.TC_tes.main(TC_tes.java:18) Caused by: java.lang.IllegalMonitorStateException: current thread not owner at java.lang.Object.wait(Native Method) at execute.TC_tes$Test.run(TC_tes.java:38) at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35) at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:123) ... 3 more です。 一秒ごとにカウントし、一定の数値に達した場合、処理を行いたいのですが、実現しません。 どなたか回避方法を教えて頂けませんでしょうか。 よろしくお願いいたします。 |
|
投稿日時: 2006-09-16 11:00
Testのwait()で例外が発生しています
同期をとる必要がないならsleepでいけますよ |
|
投稿日時: 2006-09-16 11:22
最初に。プログラムを実際に動かしたわけではないので、以下の指摘は間違っているかも知れません。
本題です。 まず、「java.lang.IllegalMonitorStateException: current thread not owner」の原因は、 class Testのrun()メソッドの「wait(1000)」です。 Object#wait(1000) は スレッドのモニタを手放して、 Object#notify()/notifyAll()が呼ばれるか1000ms経過するまで待ちます。。 waitを実行するには前もってモニタを取得する必要があります。 (具体的には、synchronizedを使う) 今回のエラーはこのこと(モニタを取得していない)ことを指摘しています (この件はjavadocのObject#wait() に書かれています。 また、より実践的なことが書籍 Effective Javaの「スレッド」の章に あると思います) もし、単に1000msの間スレッドを止めたいのであれば、Thread.sleep(long millis)を使えばよいでしょう。 次に、今回の場合、たぶんスレッドは1つしか動いていません。 「System.out.println("XXXXX: " + Thread.currentThread());」を プログラムの各所に挿入して実行すれば、確認できます。 よって、Thread.sleep(1000);を実行すると、イベントループ (main()の、while (!thisClass.aShell.isDisposed(){...})も 1000msごとにしか動作しないと思われます。 ですので、UIと無関係の処理ならJavaのTimerクラスを、 UIに描画などの処理を行うならSWTのDisplay#timerExec()を使った方がよいでしょう。 |
|
投稿日時: 2006-09-16 11:38
補足です。
もし Display#timerExec() を使われるなら、 SWTで一定時間操作がなければアプリケーションを終了したい - Java Solution でサンプルコードを投稿してます。 |
|
投稿日時: 2006-09-20 08:25
ちいにぃさん、99riさん、ありがとうございました。
また、ちいにぃさん、前回御礼をきちんとしていなかったです。すみません。ありがとうございました。 結論としてTimerexecを使用する形で回避する事にしました。 理由としては、asyncexecを使うと、砂時計が出っ放しになり、アプリケーションとして稼動させるには苦しいからです。 具体的なコードは下記のようにしました。 import java.util.Calendar; import java.util.GregorianCalendar; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Display; public class TC_tes { private Shell sShell = null; private Label clock; Calendar now = new GregorianCalendar(); public static void main(String[] args) { Display display = Display.getDefault(); TC_tes thisClass = new TC_tes(); thisClass.createSShell(); thisClass.sShell.open(); Test test = thisClass.new Test(); display.timerExec(0, test); while (!thisClass.sShell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); } private void createSShell() { sShell = new Shell(); sShell.setText("Shell"); sShell.setLayout(new FillLayout()); clock = new Label(sShell,SWT.CENTER); clockset(); sShell.pack(); } private void clockset(){ String min = new String(); if(now.get(Calendar.MINUTE)<10){min = "0"+now.get(Calendar.MINUTE);}else{min = String.valueOf(now.get(Calendar.MINUTE));} clock.setText("'"+String.valueOf(now.get(Calendar.YEAR)).substring(2)+" "+(now.get(Calendar.MONTH)+2)+"/"+now.get(Calendar.DATE)+" " +now.get(Calendar.HOUR_OF_DAY)+":"+min); } public class Test implements Runnable{ boolean min =false; public void run(){ if(min){ now.add(Calendar.MINUTE, 1); clockset(); Display.getCurrent().timerExec(60000, this); }else{ if(now.get(Calendar.SECOND)==0){ min = true; clockset(); Display.getCurrent().timerExec(60000, this); }else{ Display.getCurrent().timerExec(1000, this); } now.add(Calendar.SECOND, 1); } } } } |
1