The solution to the abnormal end of a thread in Java is: first capture the exception generated during the execution of the thread; then when the thread exception occurs, the exception will be caught by calling the setUncaughtExceptionHandler method; and finally solve it.
[Recommended tutorial: Java tutorial]
Threads are often used in our development projects. When using threads, we may have such a scenario:
(1) Along with this business, a relatively time-consuming task occurs, and this Business returns do not need to wait for the task. Then we often start a thread to complete this asynchronous task.
(2) We need a scheduled task such as clearing data regularly. We will start a scheduled execution thread to do the task.
The above problem is relatively simple, create a new thread and then do it. But we often overlook a problem, what should we do if the thread is abnormal? For example, if we only complete half of a time-consuming task, we will end it abnormally (transaction consistency is not considered here, we only consider that the task must be completed). Another example is when clearing data, the database is disconnected. At this time we will find that the thread dies and the task is terminated. We need to restart the entire project to start the scheduled task.
The key to solving these problems is how to capture exceptions generated during thread execution?
When we look at the JDK API, we will find that there is a setUncaughtExceptionHandler method in Thread, which allows us to call this method when an exception occurs in the thread.
The solution to the abnormal end of a thread in Java is:
Solution to Scenario 1:
public class Plan1 { private SimpleTask task = new SimpleTask(); public static void main(String[] args) { Plan1 plan = new Plan1(); plan.start(); } public void start(){ Thread thread = new Thread(task); //thread.setDaemon(true); //注释调 否则看不到输出 thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler(){ @Override public void uncaughtException(Thread t, Throwable e) { System.out.println(e.getMessage()); start(); } }); thread.start(); } class SimpleTask implements Runnable{ private int task = 10; @Override public void run() { String threadName = Thread.currentThread().getName(); System.out.println(threadName+"--"+"启动"); while(task>0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } if(System.currentTimeMillis()%3==0){ throw new RuntimeException("模拟异常"); } System.out.println(threadName+"--"+"执行task"+task); task--; } System.out.println(threadName+"--"+"正常终止"); } } }
Result Output:
Thread-0--启动 Thread-0--执行task10 Thread-0--执行task9 Thread-0--执行task8 Thread-0--执行task7 模拟异常 Thread-1--启动 Thread-1--执行task6 Thread-1--执行task5 模拟异常 Thread-2--启动 Thread-2--执行task4 Thread-2--执行task3 模拟异常 Thread-3--启动 Thread-3--执行task2 模拟异常 Thread-4--启动 Thread-4--执行task1 Thread-4--正常终止
Still in Scenario 1, let’s take a look at the thread pool method. The idea is the same. Why write a single-threaded thread pool method?
public class Plan3 { private SimpleTask task = new SimpleTask(); private MyFactory factory = new MyFactory(task); public static void main(String[] args) { Plan3 plan = new Plan3(); ExecutorService pool = Executors.newSingleThreadExecutor(plan.factory); pool.execute(plan.task); pool.shutdown(); } class MyFactory implements ThreadFactory{ private SimpleTask task; public MyFactory(SimpleTask task) { super(); this.task = task; } @Override public Thread newThread(Runnable r) { Thread thread = new Thread(r); thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { ExecutorService pool = Executors.newSingleThreadExecutor(new MyFactory(task)); pool.execute(task); pool.shutdown(); } }); return thread; } } class SimpleTask implements Runnable{ private int task = 10; @Override public void run() { String threadName = Thread.currentThread().getName(); System.out.println(threadName+"--"+"启动"); while(task>0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } if(System.currentTimeMillis()%3==0){ throw new RuntimeException("模拟异常"); } System.out.println(threadName+"--"+"执行task"+task); task--; } System.out.println(threadName+"--"+"正常终止"); } } }
Result output:
Thread-0--启动 Thread-0--执行task10 Thread-0--执行task9 Thread-1--启动 Thread-1--执行task8 Thread-2--启动 Thread-2--执行task7 Thread-2--执行task6 Thread-2--执行task5 Thread-2--执行task4 Thread-2--执行task3 Thread-2--执行task2 Thread-3--启动 Thread-3--执行task1 Thread-3--正常终止
Since only a single thread is used here, I found that there is not much difference from the above. However, it also shows how the thread pool catches thread exceptions.
Solution to Scenario 2
Now let’s look at the Scenario 2 scheduled task. Why should I write a single-thread pool exception catching method, which is used with the following Make comparisons.
We often use ScheduledExecutorService for scheduled tasks, which is the same as the above ExecutorService acquisition method. But if we follow the above method to write a scheduled task, and then get an exception. We will find that we cannot get the thread exception in the uncaughtException method. The exception disappears, or the uncaughtException method is not called at all when an exception occurs in the thread. Later, I checked the relevant API and found that the way to obtain exceptions in ScheduledExecutorService can be obtained using the ScheduledFuture object. The specific method is as follows:
public class Plan2 { private SimpleTask task = new SimpleTask(); public static void main(String[] args) { Plan2 plan = new Plan2(); start(plan.task); } public static void start(SimpleTask task){ ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor(); ScheduledFuture<?> future = pool.scheduleAtFixedRate(task, 0, 1000, TimeUnit.MILLISECONDS); try { future.get(); } catch (InterruptedException | ExecutionException e) { System.out.println(e.getMessage()); start(task); }finally { pool.shutdown(); } } class SimpleTask implements Runnable{ private volatile int count = 0; @Override public void run() { String threadName = Thread.currentThread().getName(); System.out.println(threadName+"--"+"启动"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } if(System.currentTimeMillis()%3==0){ throw new RuntimeException("模拟异常"); } System.out.println(threadName+"--"+"执行task"+count); count++; System.out.println(threadName+"--"+"正常终止"); } } }
Result output:
pool-1-thread-1--启动 java.lang.RuntimeException: 模拟异常 pool-2-thread-1--启动 pool-2-thread-1--执行task0 pool-2-thread-1--正常终止 pool-2-thread-1--启动 pool-2-thread-1--执行task1 pool-2-thread-1--正常终止 pool-2-thread-1--启动 pool-2-thread-1--执行task2 pool-2-thread-1--正常终止 pool-2-thread-1--启动 java.lang.RuntimeException: 模拟异常 pool-3-thread-1--启动 pool-3-thread-1--执行task3 pool-3-thread-1--正常终止 pool-3-thread-1--启动 java.lang.RuntimeException: 模拟异常 pool-4-thread-1--启动 pool-4-thread-1--执行task4 pool-4-thread-1--正常终止 .....
So far we have achieved it If an exception occurs in a scheduled task, there will always be a thread to execute it. If one thread falls, subsequent threads will take over.
The above is the detailed content of How to solve the problem of abnormal end of Java thread. For more information, please follow other related articles on the PHP Chinese website!