Cómo series Cómo darse cuenta del tiempo de espera del subproceso principal esperando el subproceso secundario (soluciones múltiples)

fondo

En algunos casos, queremos ejecutar una tarea, pero no podemos esperar a que se complete indefinidamente, sino que necesitamos obtener el resultado de la tarea dentro de un cierto rango de tiempo o decidir que la tarea se agote y tratarla en consecuencia. Este escenario suele utilizarse para lidiar con el límite de tiempo de ejecución de la tarea, evitando tareas que bloquean el hilo principal durante mucho tiempo o esperan el resultado indefinidamente.

plan

  • Thread.join (long millis)
  • Object.wait() y notificar() + bloqueo
  • FuturoTarea
  • Servicio Futuro + Ejecutor
  • Semáforo
  • pestillo de cuenta regresiva
  • CompletableFuturo
  • Guayaba SimpleTimeLimiter

Thread.join (long millis)

Si la tarea se realiza iniciando un subproceso, puede usar join(long millis)el método para hacer que el subproceso principal espere un tiempo específico antes de continuar realizando otras operaciones. join(long millis)El parámetro del método indica el tiempo máximo de espera (en milisegundos), si el hilo de la tarea no se ejecuta dentro de este tiempo, el hilo principal continuará ejecutándose. El código de ejemplo es el siguiente:

public class TimeoutExample {
    
    
    public static void main(String[] args) {
    
    
        // 启动任务线程
        Thread taskThread = new Thread(new Task());
        taskThread.start();

        try {
    
    
            // 等待任务执行结果,最多等待5秒 block
            taskThread.join(5000);
            if (taskThread.isAlive()) {
    
    
                System.out.println("任务执行超时");
                // 可以考虑中断任务线程:taskThread.interrupt();
            } else {
    
    
                System.out.println("任务执行完成");
            }
        } catch (InterruptedException e) {
    
    
            System.out.println("主线程被中断");
        }
    }
}

class Task implements Runnable {
    
    
    @Override
    public void run() {
    
    
        try {
    
    
            // 模拟耗时任务
            Thread.sleep(3000);
            System.out.println("任务完成");
        } catch (InterruptedException e) {
    
    
            System.out.println("任务被中断");
        }
    }
}

Object.wait() y notificar() + bloqueo

Este es un método tradicional de sincronización de subprocesos, que puede esperar a que la tarea se complete en el subproceso principal a través del wait()método y notify()el método, y reactivar el subproceso principal dentro del período de tiempo de espera. El código de ejemplo es el siguiente:

La atención debe cooperar con LOCK

public class TimeoutExample {
    
    
    public static void main(String[] args) {
    
    
        Object lock = new Object();

        // 启动任务线程
        new Thread(new Task(lock)).start();

        synchronized (lock) {
    
     // block
            try {
    
    
                // 等待任务执行结果,最多等待5秒
                lock.wait(5000);
                System.out.println("任务执行完成");
            } catch (InterruptedException e) {
    
    
                System.out.println("主线程被中断");
            }
        }
    }
}

class Task implements Runnable {
    
    
    private final Object lock;

    public Task(Object lock) {
    
    
        this.lock = lock;
    }

    @Override
    public void run() {
    
    
        synchronized (lock) {
    
    
            try {
    
    
                // 模拟耗时任务
                Thread.sleep(3000);
                System.out.println("任务完成");
                // 任务完成时通知主线程
                lock.notify();
            } catch (InterruptedException e) {
    
    
                System.out.println("任务被中断");
            }
        }
    }
}

FuturoTarea

Esquema de espera de tiempo de espera FutureTaskbasado en Java . ThreadEste método puede crear manualmente FutureTaskel objeto y pasar Threada realizar la tarea, y luego usar get(long timeout, TimeUnit unit)el método para establecer el tiempo máximo de espera.

public class TimeoutExample {
    
    
    public static void main(String[] args) {
    
    
        Callable<String> task = () -> {
    
    
            // 模拟耗时任务
            Thread.sleep(3000);
            return "任务完成";
        };

        // 创建FutureTask对象
        FutureTask<String> futureTask = new FutureTask<>(task);

        // 创建并启动Thread执行FutureTask
        Thread taskThread = new Thread(futureTask);
        taskThread.start();

        try {
    
    
            // 等待任务执行结果,最多等待5秒 block
            String result = futureTask.get(5, TimeUnit.SECONDS);
            System.out.println("任务执行结果:" + result);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
    
    
            System.out.println("任务执行超时或出现异常:" + e.getMessage());
            // 如果任务在5秒内没有完成,可以中断任务线程
            taskThread.interrupt();
        }
    }
}

Servicio Futuro + Ejecutor

El mecanismo de tiempo de espera se puede implementar usando ExecutorServicey . FutureDe esta forma, el subproceso principal puede esperar el resultado de la tarea, pero si la tarea no se completa dentro del tiempo especificado, el subproceso principal continuará realizando otras operaciones.

El siguiente es un código de muestra que demuestra cómo esperar el resultado de la ejecución de la tarea en el subproceso principal, pero esperar hasta 5 segundos:

public class TimeoutExample {
    
    
    public static void main(String[] args) {
    
    
        // 创建线程池
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        // 提交任务并获取Future对象
        Future<String> future = executorService.submit(new Task());

        try {
    
    
            // 等待任务执行结果,最多等待5秒 block
            String result = future.get(5, TimeUnit.SECONDS);
            System.out.println("任务执行结果:" + result);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
    
    
            // 超时或出现异常时的处理
            System.out.println("任务执行超时或出现异常:" + e.getMessage());
        } finally {
    
    
            // 关闭线程池
            executorService.shutdown();
        }
    }
}

class Task implements Callable<String> {
    
    
    @Override
    public String call() throws Exception {
    
    
        // 模拟耗时任务
        Thread.sleep(3000);
        return "任务完成";
    }
}

En el código anterior, creamos un ExecutorServicegrupo de subprocesos y enviamos una Tasktarea. A través Future.get(long timeout, TimeUnit unit)del método, esperamos el resultado de la ejecución de la tarea, hasta 5 segundos. Si la tarea se completa dentro del tiempo especificado, se puede obtener el resultado de la tarea; si la tarea no se completa dentro de los 5 segundos, se lanzará TimeoutExceptionuna excepción para que el subproceso principal pueda continuar realizando otras operaciones. Tenga en cuenta que el tiempo de ejecución real de la tarea es de 3 segundos, por lo que dentro del tiempo de espera de 5 segundos, la tarea se puede completar normalmente.

Semáforo

Semaphorees otra clase auxiliar de sincronización que controla la cantidad de subprocesos que pueden acceder simultáneamente a un recurso en particular. Podemos usarlo Semaphorecomo un semáforo para implementar el mecanismo de tiempo de espera para que el subproceso principal espere a que se complete la tarea. El código de ejemplo es el siguiente:

public class TimeoutExample {
    
    
    public static void main(String[] args) {
    
    
        // 创建Semaphore,并指定许可数量为0
        Semaphore semaphore = new Semaphore(0);

        // 启动任务线程
        new Thread(new Task(semaphore)).start();

        try {
    
    
            // 等待任务执行结果,最多等待5秒 block
            if (semaphore.tryAcquire(1, 5, TimeUnit.SECONDS)) {
    
    
                System.out.println("任务执行完成");
            } else {
    
    
                System.out.println("任务执行超时");
            }
        } catch (InterruptedException e) {
    
    
            System.out.println("主线程被中断");
        }
    }
}

class Task implements Runnable {
    
    
    private final Semaphore semaphore;

    public Task(Semaphore semaphore) {
    
    
        this.semaphore = semaphore;
    }

    @Override
    public void run() {
    
    
        try {
    
    
            // 模拟耗时任务
            Thread.sleep(3000);
            System.out.println("任务完成");
            // 任务完成时释放许可
            semaphore.release();
        } catch (InterruptedException e) {
    
    
            System.out.println("任务被中断");
        }
    }
}

pestillo de cuenta regresiva

CountDownLatchEs una clase auxiliar de sincronización que se puede usar para esperar a que se completen uno o más subprocesos. El subproceso principal puede esperar a que se complete la tarea dentro de un tiempo determinado a través del método, o llamar al método para notificar al subproceso principal await(long timeout, TimeUnit unit)cuando se complete la tarea . countDown()El código de ejemplo es el siguiente:

public class TimeoutExample {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        // 创建CountDownLatch,并指定计数器为1
        CountDownLatch latch = new CountDownLatch(1);

        // 启动任务线程
        new Thread(new Task(latch)).start();

        // 等待任务执行结果,最多等待5秒 block
        if (latch.await(5, TimeUnit.SECONDS)) {
    
    
            System.out.println("任务执行完成");
        } else {
    
    
            System.out.println("任务执行超时");
        }
    }
}

class Task implements Runnable {
    
    
    private final CountDownLatch latch;

    public Task(CountDownLatch latch) {
    
    
        this.latch = latch;
    }

    @Override
    public void run() {
    
    
        try {
    
    
            // 模拟耗时任务
            Thread.sleep(3000);
            System.out.println("任务完成");
        } catch (InterruptedException e) {
    
    
            System.out.println("任务被中断");
        } finally {
    
    
            // 任务完成时通知主线程
            latch.countDown();
        }
    }
}

CompletableFuturo

CompletableFuturees una poderosa herramienta de programación asincrónica introducida en Java 8. A través de CompletableFuture, puede implementar fácilmente tareas asincrónicas y esperar a que se completen, y usarlas CompletableFuture.get(long timeout, TimeUnit unit)para implementar la espera de tiempo de espera. El código de ejemplo es el siguiente:

public class TimeoutExample {
    
    
    public static void main(String[] args) {
    
    
        // 启动异步任务
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    
    
            try {
    
    
                // 模拟耗时任务
                Thread.sleep(3000);
                return "任务完成";
            } catch (InterruptedException e) {
    
    
                return "任务被中断";
            }
        });

        try {
    
    
            // 等待任务执行结果,最多等待5秒 block
            String result = future.get(5, TimeUnit.SECONDS);
            System.out.println(result);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
    
    
            System.out.println("任务执行超时或出现异常:" + e.getMessage());
        }
    }
}

Guayaba SimpleTimeLimiter

La biblioteca Guava (Google Guava) proporciona una SimpleTimeLimiterclase llamada para configurar y ejecutar llamadas a métodos con restricciones de tiempo de espera. Esta clase puede establecer un tiempo de ejecución máximo en un método Java y, si el método no se completa dentro del tiempo especificado, UncheckedTimeoutExceptionse lanzará una excepción. SimpleTimeLimiterAquí hay un código de muestra usando Guava :

import com.google.common.util.concurrent.SimpleTimeLimiter;
import com.google.common.util.concurrent.UncheckedTimeoutException;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class TimeoutExample {
    
    
    public static void main(String[] args) {
    
    
        // 创建ExecutorService线程池
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        // 创建SimpleTimeLimiter对象
        SimpleTimeLimiter timeLimiter = SimpleTimeLimiter.create(executorService);

        // 定义一个耗时任务
        Callable<String> task = () -> {
    
    
            // 模拟耗时任务
            Thread.sleep(3000);
            return "任务完成";
        };

        try {
    
    
            // 使用SimpleTimeLimiter执行任务,最多等待5秒 block
            String result = timeLimiter.callWithTimeout(task, 5, TimeUnit.SECONDS);
            System.out.println("任务执行结果:" + result);
        } catch (UncheckedTimeoutException e) {
    
    
            System.out.println("任务执行超时:" + e.getMessage());
        } catch (Exception e) {
    
    
            System.out.println("任务执行出现异常:" + e.getMessage());
        } finally {
    
    
            // 关闭线程池
            executorService.shutdown();
        }
    }
}

Supongo que te gusta

Origin blog.csdn.net/abu935009066/article/details/132096779
Recomendado
Clasificación