J'ai un Y a-t-il un moyen standard d'attendre la tâche de fond en réalité em> finition? Je cherche à montrer un message "Annulation ..." ou quelque chose du genre et du bloc jusqu'à la résiliation de la tâche. (Je suis sûr que je pouvais toujours y accomplir avec un drapeau dans la classe ouvrière si nécessaire, à la recherche de toute autre solution.) P> swingworker code> qui appelle du code qui ne vérifie pas l'interruption de thread. Après l'appel à
travailleur.cancel (true) code>, le
ouvrier.get.get () code> Method va lancer
CANCellationException code> immédiatement (comme cela est censé) . Cependant, étant donné que le code de la tâche d'arrière-plan ne vérifie jamais son thread à interrompre, il continue joliment d'exécuter. P>
3 Réponses :
La chose la plus proche à une manière standard ou prêt à faire de cela est la propriété code> Progress ou la paire de méthodes de publication / processus fournie par Voici quelques exemples de code qui exécute un fil de fond obstiné, qui est annulé et puis attend jusqu'à ce que la progression atteigne 100. p> swingworker code>. Vous pouvez définir cela sur une valeur "J'ai fini" à la fin de la méthode pour indiquer que les travaux d'arrière-plan sont effectués. Le fil d'attente sur le travailleur oscillant peut poser un message "Annulation ..." et vérifier périodiquement les progrès pour voir si elle a atteint l'achèvement. Si le fil d'attente est le swing Edt, vous devrez alors utiliser une minuterie pour vérifier périodiquement la propriété de progression et effacer le message d'annulation lorsque vous avez terminé.
@Test
public void testSwingWorker()
{
SwingWorker worker = new SwingWorker() {
@Override
protected void process(List chunks)
{
for (Object chunk : chunks)
{
System.out.println("process: "+chunk.toString());
}
}
@Override
protected void done()
{
System.out.println("done");
}
@Override
protected Object doInBackground() throws Exception
{
// simulate long running method
for (int i=0; i<1000000000; i++)
{
double d = Math.sqrt(i);
}
System.err.println("finished");
publish("finished");
setProgress(100);
return null;
}
};
Thread t = new Thread(worker);
t.start();
try
{
worker.get(1, TimeUnit.SECONDS);
}
catch (InterruptedException e) {
}
catch (ExecutionException e) {
}
catch (TimeoutException e) {
}
worker.cancel(true);
// now wait for finish.
int progress = 0;
do
{
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
}
progress = worker.getProgress();
System.out.println(String.format("progress %d", progress));
}
while (progress<100);
}
Ces deux idées sont des choses que je n'avais pas encore envisagées. Je n'aime pas utiliser les progrès pour la même raison que vous avez citées - cela nécessite un sondage. J'aime l'idée de publication / processus pour la plupart, mais il coule la logique que je veux faire lorsque la tâche est réellement i> fini sur la classe swingworker code> la classe elle-même. Pour cette même raison, j'utilise rarement la méthode
terminée () CODE> et ajoutez généralement des auditeurs à l'objet travailleur.
Je suis d'accord avec vous, publie / processus est le meilleur des deux. En ce qui concerne le couplage, vous pouvez le découper en créant une sous-classe SwingWorker qui remplace la méthode de processus, écoute la valeur «J'ai terminé» et informez les auditeurs inscrits que la tâche de fond est réellement effectuée. Cela sépare la logique de l'ouvrier battant.
True, mais alors comment l'objet d'écoute serait-il entre-temps entre-temps jusqu'à ce qu'il reçoive la notification?
J'avais supposé que la logique serait exécutée sur l'EDT - c'est la force de l'utilisation de publications / processus - il saute les données publiées du fil de fond à l'EDT. Si vous avez besoin d'un thread séparé pour bloquer à la fin, enregistrez-vous un auditeur, qui contient le coundownlatch de votre propre réponse. Lorsqu'il est notifié, l'auditeur déclenche le loquet de compte à rebours, permettant ainsi au fil d'attente de continuer.
J'ai compris. Étant donné que le fil d'attente est l'EDT et qu'il bloque probablement en raison de la boîte de dialogue "Annulation ...", l'auditeur que vous parlez de ce qui fermerait la boîte de dialogue, ce qui empêche ainsi l'EDT. Cela dit, je ne suis toujours pas vendu à 100% sur cette option, au cas où le SwingWorker code> J'utilise est en réalité en utilisant la publication / processus à un autre but.
J'ai joué un peu et voici ce que je suis venu. J'utilise un compte à rebours code> et expose essentiellement son
attendre () code> méthode sous forme de méthode sur mon
swingworker code> objet. Toujours à la recherche de meilleures solutions.
final class Worker extends SwingWorker<Void, Void> {
private final CountDownLatch actuallyFinishedLatch = new CountDownLatch(1);
@Override
protected Void doInBackground() throws Exception {
try {
System.out.println("Long Task Started");
/* Simulate long running method */
for (int i = 0; i < 1000000000; i++) {
double d = Math.sqrt(i);
}
return null;
} finally {
actuallyFinishedLatch.countDown();
}
}
public void awaitActualCompletion() throws InterruptedException {
actuallyFinishedLatch.await();
}
public static void main(String[] args) {
Worker worker = new Worker();
worker.execute();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
}
System.out.println("Cancelling");
worker.cancel(true);
try {
worker.get();
} catch (CancellationException e) {
System.out.println("CancellationException properly thrown");
} catch (InterruptedException e) {
} catch (ExecutionException e) {
}
System.out.println("Awaiting Actual Completion");
try {
worker.awaitActualCompletion();
System.out.println("Done");
} catch (InterruptedException e) {
}
}
}
Inspiré par la solution de Paul Béning, je l'ai un peu amélioré pour devenir une classe, vous pouvez sous-classe pour obtenir la funcitonalité souhaitée:
class AwaitingWorker<T,V> extends SwingWorker<T, V> { private final CountDownLatch actuallyFinishedLatch = new CountDownLatch(1); /** * Override this to do something useful */ protected abstract void performOperation(); @Override protected final T doInBackground() throws Exception { try { return performOperation(); } finally { actuallyFinishedLatch.countDown(); } } public void awaitActualCompletion() throws InterruptedException { actuallyFinishedLatch.await(); } }
Je suppose que Cadré () appelle maintenant attendez-vousComplet () mais maintenant fait () peut être une tâche de course longue, car elle attend autour d'attendre que DoIndbackground () soit terminée après avoir été annulé avec Annuler (). Il va bloquer l'événementDispatThread
N'est-il pas possible d'annuler une tâche programmée pour l'exécution mais n'a pas été lancée? On dirait que l'attente d'exécution a besoin de vérifier en quelque sorte qu'une tâche n'a pas été annulée avant son départ avant d'appeler attendre.