Naprawdę, nie możesz ... Jedynym sposobem, aby to zrobić, jest użycie thread.stop, uzgodnienie metody "współpracy" (np. Sprawdzanie okazyjnie dla Thread.isInterrupted lub wywoływanie metody powodującej wyjątek InterruptedException , np. Thread.sleep()), lub w jakiś sposób wywołać metodę w innej maszynie JVM całkowicie.
Dla niektórych rodzajów testów wywołanie metody stop() jest w porządku, ale prawdopodobnie spowoduje to uszkodzenie stanu zestawu testowego, więc po każdym wywołaniu należy ponownie uruchomić maszynę JVM(), jeśli chcesz uniknąć efekty interakcji.
Aby dobrze opisać, jak wdrożyć podejście oparte na współpracy, należy zapoznać się z Sun's FAQ on the deprecated Thread methods.
Dla przykładu tego podejścia w rzeczywistości, obiekt "IProgressMonitor" pozwala niektórym służbom zarządzającym sygnalizować podprocesy (za pomocą metody "anulowania"), że powinny się zatrzymać. Oczywiście opiera się to na metodach faktycznego sprawdzania metody isCancelled regularnie, czego często nie robią.
Podejście hybrydowe może polegać na ładnym zadawaniu pytania z przerwaniem, a następnie naleganiu kilka sekund później z zatrzymaniem. Ponownie, nie powinieneś używać stopu w kodzie produkcyjnym, ale może to być w porządku w tym przypadku, szczególnie. jeśli wkrótce opuścisz maszynę JVM.
Aby przetestować to podejście, napisałem prostą wiązkę, która uruchamia się i próbuje ją wykonać. Zapraszam do komentowania/edycji.
public void testStop(Runnable r) {
Thread t = new Thread(r);
t.start();
try {
t.join(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (!t.isAlive()) {
System.err.println("Finished on time.");
return;
}
try {
t.interrupt();
t.join(2000);
if (!t.isAlive()) {
System.err.println("cooperative stop");
return;
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.err.println("non-cooperative stop");
StackTraceElement[] trace = Thread.getAllStackTraces().get(t);
if (null != trace) {
Throwable temp = new Throwable();
temp.setStackTrace(trace);
temp.printStackTrace();
}
t.stop();
System.err.println("stopped non-cooperative thread");
}
By to sprawdzić, napisałem dwa konkurujące ze sobą nieskończone pętle, jedna spółdzielni, i jeden, który nie sprawdza wątku przerwaną trochę.
public void cooperative() {
try {
for (;;) {
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.err.println("cooperative() interrupted");
} finally {
System.err.println("cooperative() finally");
}
}
public void noncooperative() {
try {
for (;;) {
Thread.yield();
}
} finally {
System.err.println("noncooperative() finally");
}
}
Wreszcie napisałem testy (JUnit 4) wykonywać je:
@Test
public void testStopCooperative() {
testStop(new Runnable() {
@Override
public void run() {
cooperative();
}
});
}
@Test
public void testStopNoncooperative() {
testStop(new Runnable() {
@Override
public void run() {
noncooperative();
}
});
}
nigdy nie używany Thread.stop() przed, więc byłem nieświadomy jego funkcjonowania. Działa poprzez rzucanie obiektu ThreadDeath z dowolnego miejsca, w którym aktualnie uruchomiony jest wątek docelowy. To rozszerza błąd. Tak więc, choć nie zawsze działa to czysto, zwykle pozostawia proste programy z dość rozsądnym stanem programu. Na przykład wywoływane są wszystkie bloki końcowe. Jeśli chcesz być prawdziwym palantem, możesz złapać ThreadDeath (lub Error), i nadal działać, tak!
Jeśli nic więcej, to naprawdę sprawia, że chcą więcej kodu następuje podejście IProgressMonitor - Dodanie kolejnego parametru do metod, które może potrwać i zachęcającą implementor metody od czasu do czasu odpytywać monitor obiektu, aby sprawdzić, czy użytkownik chce, aby system się poddał. Spróbuję nadążyć za tym wzorem w przyszłości, szczególnie metody, które mogą być interaktywne. Oczywiście, nie zawsze wiesz z góry, które metody będą używane w ten sposób, ale do tego właśnie służą Profilery.
Jeśli chodzi o metodę "rozpocznij zupełnie inną maszynę JVM", zajmie to więcej pracy. Nie wiem, czy ktoś napisał delegujący moduł ładujący, lub jeśli jest uwzględniony w JVM, ale to byłoby wymagane w tym podejściu.
dzięki za odpowiedź. w tym przypadku funkcja nie może być zaprojektowana do okresowego sprawdzania wartości podstawowej lub synchronizacji. – carrier