當您希望某個任務由另一個線程執行時,可以擴展Thread或實現Runnable。Java:完全在第二個線程中運行的類/ IllegalMonitorStateException
我試圖創建一個完全在第二個線程中運行一個類的類。
這意味着你可以調用anyMethod(),它立即返回,並由第二個線程執行。
這裏是我的嘗試:
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* Extend this class to run method calls asynchronously in the second thread implemented by this class.
* Create method(type1 param1, type2 param2, ...) and let it call this.enqueueVoidCall("method", param1, param2, ...)
*
* The thread executing the run-method will automatically call methodAsync with the specified parameters.
* To obtain the return-value, pass an implementation of AsyncCallback to this.enqueueCall().
* AsyncCallback.returnValue() will automatically be called upon completion of the methodAsync.
*
*/
public class ThreadedClass extends Thread {
private static Object test;
private Queue<String> queue_methods = new ConcurrentLinkedQueue<String>();
private Queue<Object[]> queue_params = new ConcurrentLinkedQueue<Object[]>();
private Queue<AsyncCallback<? extends Object>> queue_callback = new ConcurrentLinkedQueue<AsyncCallback<? extends Object>>();
private volatile boolean shutdown = false;
/**
* The run method required by Runnable. It manages the asynchronous calls placed to this class.
*/
@Override
public final void run() {
test = new Object();
while (!shutdown) {
if (!this.queue_methods.isEmpty()) {
String crtMethod = queue_methods.poll();
Object[] crtParamArr = queue_params.poll();
String methodName = crtMethod + "Async";
Method method;
try {
method = this.getClass().getMethod(methodName);
try {
Object retVal = method.invoke(this, crtParamArr);
AsyncCallback<? extends Object> crtCallback = queue_callback.poll();
crtCallback.returnValue(retVal);
} catch (Exception ex) {}
} catch (SecurityException ex) {
} catch (NoSuchMethodException ex) {}
} else {
try {
synchronized(test) {
test.wait();
}
} catch (InterruptedException ex) {
System.out.println("READY");
} catch (Exception ex) {
System.out.println("READY, but " + ex.getMessage());
}
}
}
}
/**
* Asynchronously adds a method-call to the scheduler, specified by methodName with passed parameters
* @param methodName The name of the currently called method. methodName + "Async" is being called
* @param parameters Parameters you may want to pass to the method
*/
protected final void enqueueVoidCall(String methodName, Object... parameters) {
List<Object> tmpParam = new ArrayList<Object>();
for (Object crt : parameters) {
tmpParam.add(crt);
}
queue_methods.add(methodName);
queue_params.add(parameters);
queue_callback.add(null);
test.notifyAll();
}
/**
* Asynchronously adds a method-call to the scheduler, specified by methodName with passed parameters
* @param methodName The name of the currently called method. methodName + "Async" is being called
* @param callBack An instance of AsyncCallback whose returnValue-method is called upon completion of the task.
* @param parameters Parameters you may want to pass to the method
*/
protected final void enqueueCall(String methodName, AsyncCallback<? extends Object> callBack, Object... parameters) {
List<Object> tmpParam = new ArrayList<Object>();
for (Object crt : parameters) {
tmpParam.add(crt);
}
queue_methods.add(methodName);
queue_params.add(parameters);
queue_callback.add(callBack);
test.notifyAll();
}
/**
* Complete the currently running task, optionally return values and eventually shut down. The instance of this object becomes unusable after this call.
*/
public void shutdown() {
shutdown=true;
}
}
現在我有兩個類來測試的東西:
public class MySecondTask extends ThreadedClass {
public void test1() {
this.enqueueVoidCall("test1", null);
}
public void test1Async() {
System.out.println("Start");
try {
// do big job here
} catch (Exception ex) { }
System.out.println("Done");
}
}
和主方法開始的東西:
public class TestingClass {
public static void main(String[] args) {
MySecondTask test = new MySecondTask();
test.start();
System.out.println("1. Thread [1]");
// CORRECTION, SHOULD BE:
test.test1();
// INSTEAD OF:
// test.test1Async();
for(int q=0; q<=100000; q++) {
System.out.println("1:"+ new Date().getTime()+":"+ q);
if ((q % 1000) == 0) {
System.out.flush();
}
}
System.err.println("1. Thread [2]");
}
}
不知何故,第二個線程的輸出總是首先(完全)出現,然後剩下的放在控制檯上。如果線程同時運行(這是預期的結果),控制檯輸出應該混合?!
任何想法是讚賞以及評論,以改善我的編碼風格。
編輯:
引用的問題是相當解決。
現在我收到一個IllegalMonitorStateException,在我打電話的地方:ThreadedClass.notifyAll()。
也許我得到了一個錯誤的鎖。但是a)爲什麼需要在wait()方法中使用synchronized()以及如何使notifyAll() - 調用來取消阻塞wait()?
在此先感謝和問候
P.S:你們都在堆棧溢出做好。你已經幫助了我很多次而不知道它,謝謝你。保持!
TestingClass.main()中是否有錯誤?我沒有看到它調用test1()的任何地方。 – 2009-07-27 21:14:52
等一下,你從哪裏得到這個:AsyncCallback對象,它不是Java的一部分 – OscarRyz 2009-07-28 00:39:34