Future.cancel în Java

Anulează o sarcină: dacă nu a pornit, nu mai rulează; dacă rulează, o poate întrerupe.

Sintaxă
boolean cancel(boolean intrerupeDacaRuleaza)
boolean isCancelled()

Ce face Future.cancel

cancel încearcă să anuleze sarcina din spatele unui Future. Dacă sarcina stă încă la coadă, nu mai pornește deloc. Dacă rulează deja, parametrul decide: cu true firul ei este întrerupt (primește InterruptedException în sleep, wait etc.), cu false este lăsată să se termine.

cancel returnează false dacă sarcina s-a terminat deja sau a fost deja anulată. După o anulare reușită, isCancelled() și isDone() sunt true, iar get() aruncă CancellationException.

Întreruperea este o cerere, nu o oprire forțată: o sarcină care doar calculează fără să verifice Thread.interrupted() continuă să ruleze.

Parametri

Parametru Descriere
intrerupeDacaRuleaza true ca să întrerupă firul care rulează deja sarcina; false ca doar să o împiedice să pornească.

Ce returnează

true dacă anularea a reușit, false dacă sarcina era deja terminată sau anulată.

Exemple

Exemplul 1: Anularea unei descărcări lungi

import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Main {
    public static void main(String[] args) throws Exception {
        try (ExecutorService executor = Executors.newSingleThreadExecutor()) {
            Future<String> descarcare = executor.submit(() -> {
                Thread.sleep(10_000);
                return "film.mp4";
            });
            Thread.sleep(100);
            System.out.println("Anulare reușită: " + descarcare.cancel(true));
            System.out.println("isCancelled: " + descarcare.isCancelled() + ", isDone: " + descarcare.isDone());
            System.out.println("A doua anulare: " + descarcare.cancel(true));
            try {
                descarcare.get();
            } catch (CancellationException e) {
                System.out.println("get() aruncă CancellationException");
            }
        }
    }
}

Rezultat

Anulare reușită: true
isCancelled: true, isDone: true
A doua anulare: false
get() aruncă CancellationException

Exemplul 2: O sarcină terminată nu se mai poate anula

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Main {
    public static void main(String[] args) throws Exception {
        try (ExecutorService executor = Executors.newSingleThreadExecutor()) {
            Future<Integer> suma = executor.submit(() -> 150 + 250);
            System.out.println("Rezultat: " + suma.get());
            System.out.println("cancel după terminare: " + suma.cancel(true));
            System.out.println("isCancelled: " + suma.isCancelled());
        }
    }
}

Rezultat

Rezultat: 400
cancel după terminare: false
isCancelled: false

Exemplul 3: Sarcina care nu a pornit încă

Executorul are un singur fir, ocupat cu prima sarcină. A doua stă la coadă și este anulată înainte să pornească, deci mesajul ei nu apare.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Main {
    public static void main(String[] args) throws Exception {
        try (ExecutorService executor = Executors.newSingleThreadExecutor()) {
            Future<?> prima = executor.submit(() -> {
                Thread.sleep(300);
                System.out.println("Prima sarcină s-a terminat");
                return null;
            });
            Future<?> aDoua = executor.submit(() -> System.out.println("A doua sarcină a rulat"));
            System.out.println("Anulez a doua: " + aDoua.cancel(false));
            prima.get();
        }
    }
}

Rezultat

Anulez a doua: true
Prima sarcină s-a terminat

Greșeli frecvente

  • Crezi că cancel(true) oprește orice cod. Oprește doar codul care reacționează la întrerupere (sleep, wait, I/O întreruptibil sau verificări Thread.interrupted()).
  • Apelezi get() după cancel fără să prinzi CancellationException.

Comenzi înrudite

  • Future: Rezultatul unei sarcini care rulează pe alt fir: get() așteaptă și îl returnează, isDone() spune dacă s-a terminat.
  • ExecutorService.submit: Trimite o sarcină executorului și returnează imediat un Future din care iei mai târziu rezultatul.
  • Executors.newScheduledThreadPool: Creează un executor care rulează sarcini după o întârziere sau periodic (la fiecare N secunde).