How to series How to realize the timeout of the main thread waiting for the child thread (multiple solutions)

background

In some cases, we want to execute a task, but we can't wait for its completion indefinitely, but need to get the result of the task within a certain time range or decide that the task times out and deal with it accordingly. This scenario is usually used to deal with the time limit of task execution, avoiding tasks that block the main thread for a long time or wait for the result indefinitely.

plan

  • Thread.join(long millis)
  • Object.wait() and notify() + lock
  • FutureTask
  • Future + ExecutorService
  • Semaphore
  • CountDownLatch
  • CompletableFuture
  • Guava SimpleTimeLimiter

Thread.join(long millis)

If the task is performed by starting a thread, you can use join(long millis)the method to make the main thread wait for a specified time before continuing to perform other operations. join(long millis)The parameter of the method indicates the maximum waiting time (in milliseconds). If the task thread is not executed within this time, the main thread will continue to execute. The sample code is as follows:

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() and notify() + lock

This is a traditional thread synchronization method, which can wait for the task to complete in the main thread through the wait()method and notify()method, and wake up the main thread within the timeout period. The sample code is as follows:

Attention must cooperate with 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("任务被中断");
            }
        }
    }
}

FutureTask

Java-based FutureTaskand Threadtimeout waiting scheme. This method can manually create FutureTaskthe object and pass Threadto perform the task, and then use get(long timeout, TimeUnit unit)the method to set the maximum waiting time.

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();
        }
    }
}

Future + ExecutorService

The timeout mechanism can be implemented using ExecutorServiceand . FutureIn this way, the main thread can wait for the result of the task, but if the task is not completed within the specified time, the main thread will continue to perform other operations.

The following is a sample code that demonstrates how to wait for the execution result of the task in the main thread, but wait up to 5 seconds:

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 "任务完成";
    }
}

In the above code, we create a ExecutorServicethread pool and submit a Tasktask. Through Future.get(long timeout, TimeUnit unit)the method, we wait for the execution result of the task, up to 5 seconds. If the task is completed within the specified time, the result of the task can be obtained; if the task is not completed within 5 seconds, TimeoutExceptionan exception will be thrown, so that the main thread can continue to perform other operations. Note that the actual execution time of the task is 3 seconds, so within the timeout of 5 seconds, the task can be completed normally.

Semaphore

Semaphoreis another synchronization helper class that controls the number of threads that can simultaneously access a particular resource. We can use it Semaphoreas a semaphore to implement the timeout mechanism for the main thread to wait for the task to complete. The sample code is as follows:

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("任务被中断");
        }
    }
}

CountDownLatch

CountDownLatchIs a synchronization helper class that can be used to wait for one or more threads to complete. The main thread can wait for the task within a certain time to complete through the method, or call the method to notify the main thread await(long timeout, TimeUnit unit)when the task is completed . countDown()The sample code is as follows:

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();
        }
    }
}

CompletableFuture

CompletableFutureis a powerful asynchronous programming tool introduced in Java 8. Through CompletableFuture, you can easily implement asynchronous tasks and wait for their completion, and use them CompletableFuture.get(long timeout, TimeUnit unit)to implement timeout waiting. The sample code is as follows:

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());
        }
    }
}

Guava SimpleTimeLimiter

The Guava library (Google Guava) provides a SimpleTimeLimiterclass called for setting and executing method calls with timeout constraints. This class can set a maximum execution time on a Java method, and if the method does not complete within the specified time, UncheckedTimeoutExceptionan exception will be thrown. SimpleTimeLimiterHere is sample code using 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();
        }
    }
}

Guess you like

Origin blog.csdn.net/abu935009066/article/details/132096779