- PR -

asyncExec(Runnable)でwaitを使用すると、「current thread not owner」となってしまう

1
投稿者投稿内容
しんい
ベテラン
会議室デビュー日: 2005/09/01
投稿数: 55
投稿日時: 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

です。
一秒ごとにカウントし、一定の数値に達した場合、処理を行いたいのですが、実現しません。
どなたか回避方法を教えて頂けませんでしょうか。
よろしくお願いいたします。
99ri
大ベテラン
会議室デビュー日: 2006/09/09
投稿数: 129
投稿日時: 2006-09-16 11:00
Testのwait()で例外が発生しています
同期をとる必要がないならsleepでいけますよ
ちいにぃ
大ベテラン
会議室デビュー日: 2002/05/28
投稿数: 244
投稿日時: 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()を使った方がよいでしょう。
ちいにぃ
大ベテラン
会議室デビュー日: 2002/05/28
投稿数: 244
投稿日時: 2006-09-16 11:38
補足です。

もし Display#timerExec() を使われるなら、
SWTで一定時間操作がなければアプリケーションを終了したい - Java Solution
でサンプルコードを投稿してます。
しんい
ベテラン
会議室デビュー日: 2005/09/01
投稿数: 55
投稿日時: 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

スキルアップ/キャリアアップ(JOB@IT)