Heim  >  Artikel  >  Java  >  So lösen Sie das Problem des abnormalen Endes des Java-Threads

So lösen Sie das Problem des abnormalen Endes des Java-Threads

清浅
清浅Original
2019-04-25 14:18:295736Durchsuche

Die Lösung für das abnormale Ende eines Threads in Java besteht darin, zuerst die während der Ausführung des Threads generierte Ausnahme zu erfassen. Wenn der Thread dann abnormal ist, wird die Ausnahme durch Aufrufen der setUncaughtExceptionHandler-Methode abgefangen löse es endlich.

So lösen Sie das Problem des abnormalen Endes des Java-Threads

[Empfohlenes Tutorial: Java-Tutorial]

Threads werden häufig in unseren Entwicklungsprojekten verwendet. Bei der Verwendung von Threads können die folgenden Szenarien auftreten:

(1) Zusammen mit diesem Geschäft entsteht eine relativ zeitaufwändige Aufgabe, und zwar Geschäftsrücksendungen müssen nicht auf die Aufgabe warten. Dann starten wir oft einen Thread, um diese asynchrone Aufgabe abzuschließen.

(2) Wir benötigen eine geplante Aufgabe, z. B. das regelmäßige Löschen von Daten. Wir werden einen geplanten Ausführungsthread starten, um die Aufgabe zu erledigen.

Das obige Problem ist relativ einfach: Erstellen Sie einen neuen Thread und führen Sie ihn dann aus. Aber wir übersehen oft ein Problem. Was sollen wir tun, wenn der Thread abnormal ist? Wenn wir beispielsweise nur die Hälfte einer zeitaufwändigen Aufgabe abschließen, beenden wir sie abnormal (die Transaktionskonsistenz wird hier nicht berücksichtigt, wir gehen nur davon aus, dass die Aufgabe abgeschlossen werden muss). Ein weiteres Beispiel ist, dass beim Löschen von Daten die Verbindung zur Datenbank getrennt wird. Zu diesem Zeitpunkt werden wir feststellen, dass der Thread stirbt und die Aufgabe beendet wird. Wir müssen das gesamte Projekt neu starten, um die geplante Aufgabe zu starten.

Der Schlüssel zur Lösung dieser Probleme liegt darin, wie Ausnahmen erfasst werden, die während der Thread-Ausführung generiert werden.

Wenn wir uns die JDK-API ansehen, werden wir feststellen, dass es in Thread eine setUncaughtExceptionHandler-Methode gibt, die es uns ermöglicht, diese Methode aufzurufen, wenn eine Ausnahme im Thread auftritt.

Die Lösung für ein abnormales Thread-Ende in Java ist:

Szenario 1 Lösung:

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+"--"+"正常终止");
        }
    }
}

Ergebnisausgabe :

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--正常终止

Schauen wir uns noch in Szenario 1 die Thread-Pool-Methode an. Die Idee ist dieselbe. Warum eine Single-Thread-Thread-Pool-Methode schreiben?

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+"--"+"正常终止");
        }
    }
}

Ergebnisausgabe:

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--正常终止

Da hier nur ein einzelner Thread verwendet wird, habe ich festgestellt, dass es keinen großen Unterschied zu den oben genannten gibt. Es zeigt jedoch auch, wie der Thread-Pool Thread-Ausnahmen abfängt.

Lösung für Szenario 2

Sehen wir uns nun die geplanten Aufgaben für Szenario 2 an. Warum sollte ich eine Single-Thread-Pool-Ausnahmeabfangmethode schreiben, die wie folgt verwendet wird? Vergleiche.

Wir verwenden häufig ScheduledExecutorService für geplante Aufgaben, was mit der oben genannten ExecutorService-Erfassungsmethode identisch ist. Wenn wir jedoch der oben beschriebenen Methode folgen, um eine geplante Aufgabe zu schreiben, erhalten wir eine Ausnahme. Wir werden feststellen, dass wir die Thread-Ausnahme in der uncaughtException-Methode nicht erhalten können. Die Ausnahme verschwindet oder die uncaughtException-Methode wird überhaupt nicht aufgerufen, wenn im Thread eine Ausnahme auftritt. Später habe ich die entsprechende API überprüft und festgestellt, dass die Möglichkeit, Ausnahmen in ScheduledExecutorService zu erhalten, mithilfe des ScheduledFuture-Objekts abgerufen werden kann. Die spezifische Methode lautet wie folgt:

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+"--"+"正常终止");
        }
    }
}

Ergebnisausgabe:

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--正常终止
.....

Bisher haben wir es geschafft. Wenn in einer geplanten Aufgabe eine Ausnahme auftritt, gibt es immer einen Thread, der diese ausführt. Fällt ein Thread aus, übernehmen die nachfolgenden Threads die Führung.

Das obige ist der detaillierte Inhalt vonSo lösen Sie das Problem des abnormalen Endes des Java-Threads. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Vorheriger Artikel:Was ist Javaee?Nächster Artikel:Was ist Javaee?