更加強健的線程模型,解決線程卡死,退出異常情況


線程模型

 1 package net.sz;
 2 
 3 import java.util.Random;
 4 import java.util.concurrent.ConcurrentLinkedQueue;
 5 import org.apache.log4j.Logger;
 6 
 7 /**
 8  *
 9  * <br>
10  * author 失足程序員<br>
11  * mail 492794628@qq.com<br>
12  * phone 13882122019<br>
13  */
14 public class ThreadTest implements Runnable {
15 
16     private static final Logger log = Logger.getLogger(ThreadTest.class);
17 
18     public ConcurrentLinkedQueue<Runnable> runs = new ConcurrentLinkedQueue<>();
19 
20     Runnable run;
21     long lastTimer;
22 
23     @Override
24     public void run() {
25         while (true) {
26             run = null;
27             lastTimer = 0;
28             try {
29                 /*如果隊列為空強制線程等待*/
30                 while (runs.isEmpty()) {
31                     synchronized (runs) {
32                         /*直到收到通知消息*/
33                         runs.wait();
34                     }
35                 }
36 
37                 /*取出任務*/
38                 run = runs.poll();
39                 lastTimer = System.currentTimeMillis();
40                 if (run != null) {
41                     /*執行任務*/
42                     run.run();
43                 }
44             } catch (Exception e) {
45                 /*捕獲異常*/
46                 log.error("", e);
47             }
48         }
49     }
50 }

我相信這段代碼,70%左右的java開發人員,在線程隊列執行的線程,線程模型都是這樣設計的

我也是,而且這樣的代碼持續了很多年;

線程執行 Runnable 接口實現,內部封裝了任務列表,

線程執行的時候取出隊列里面第一個,執行,

之所以加上開始執行時間就是為了檢查當前線程對象執行任務的時候卡死了,比如一直等待;

並且在死循環里面添加了 try catch 捕獲異常現象;

看上去連線程退出的機會都沒有了是不是呢?

感覺沒啥問題啊, 接下來我們看看

線程模型使用

 1 public class TestMain {
 2 
 3     private static final Logger log = Logger.getLogger(TestMain.class);
 4     static ThreadTest threadTest = new ThreadTest();
 5 
 6     public static void main(String[] args) throws InterruptedException {
 7         /*創建線程任務隊列*/
 8         Thread thread = new Thread(threadTest);
 9         /*啟動線程*/
10         thread.start();
11         long i = 0;
12 
13         Random random = new Random();
14 
15         Thread thread1 = new Thread(new Runnable() {
16             @Override
17             public void run() {
18                 while (true) {
19                     try {
20                         /*相當於沒 2秒 有一個任務需要處理*/
21                         Thread.sleep(2000);
22                     } catch (Exception e) {
23                     }
24                     /*創建任務*/
25                     threadTest.runs.add(new Runnable() {
26                         @Override
27                         public void run() {
28                             int nextInt = random.nextInt(10000);
29                             if (nextInt < 2000) {
30                                 try {
31                                     /*相當於有20%的概率暫停 5秒 模擬任務的執行耗時*/
32                                     Thread.sleep(5000);
33                                 } catch (Exception e) {
34                                 }
35                             } else if (nextInt < 5000) {
36                                 try {
37                                     /*相當於有50%的概率暫停 2秒 模擬任務的執行耗時*/
38                                     Thread.sleep(2000);
39                                 } catch (Exception e) {
40                                 }
41                             }
42                             log.error(System.currentTimeMillis());
43                         }
44                     });
45                     /*通知線程有新任務了*/
46                     synchronized (threadTest.runs) {
47                         threadTest.runs.notify();
48                     }
49                 }
50             }
51         });
52         thread1.start();
53         while (true) {
54             try {
55                 /*相當於沒 1秒 檢查*/
56                 Thread.sleep(1000);
57             } catch (Exception e) {
58             }
59             long timer = System.currentTimeMillis() - threadTest.lastTimer;
60             if (threadTest.lastRun != null) {
61                 if (timer > 500) {
62                     log.error("線程可能已卡死:" + timer);
63                 } else {
64                     log.error("線程執行耗時:" + timer);
65                 }
66             }
67         }
68     }
69 }
View Code

 

以上代碼,我們線程在處理隊列任務的時候使用的一般情況

[01-20 15:43:10:0544:ERROR: sz.TestMain.run():93 ] -> 1484898190544
[01-20 15:43:10:0544:ERROR: sz.TestMain.run():93 ] -> 1484898190544
[01-20 15:43:10:0557:ERROR: sz.TestMain.main():115] -> 線程執行耗時:13
[01-20 15:43:11:0557:ERROR: sz.TestMain.main():113] -> 線程可能已卡死:1013
[01-20 15:43:12:0544:ERROR: sz.TestMain.run():93 ] -> 1484898192544
[01-20 15:43:12:0558:ERROR: sz.TestMain.main():115] -> 線程執行耗時:14
[01-20 15:43:13:0558:ERROR: sz.TestMain.main():113] -> 線程可能已卡死:1014
[01-20 15:43:14:0545:ERROR: sz.TestMain.run():93 ] -> 1484898194545
[01-20 15:43:14:0545:ERROR: sz.TestMain.run():93 ] -> 1484898194545
[01-20 15:43:14:0545:ERROR: sz.TestMain.run():93 ] -> 1484898194545
[01-20 15:43:14:0545:ERROR: sz.TestMain.run():93 ] -> 1484898194545
[01-20 15:43:16:0559:ERROR: sz.TestMain.main():115] -> 線程執行耗時:13
[01-20 15:43:17:0559:ERROR: sz.TestMain.main():113] -> 線程可能已卡死:1013

這些都是我在模擬線程執行流程操作完全沒有問題,

可能很多看過我之前代碼的童鞋也知道,我的線程模型一直都是這么定義,這么使用的;

並且使用了很多年,我有理由相信很多小伙伴都是這樣寫的!

如果是請請舉個爪。恩,扥,對,我是這樣的

好吧接下來我們改造一下拋錯異常,處理

線程執行任務的時候總有可能拋錯異常對不對;

拋出異常的線程任務

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        /*相當於沒 2秒 有一個任務需要處理*/
                        Thread.sleep(2000);
                    } catch (Exception e) {
                    }
                    /*創建任務*/
                    threadTest.runs.add(new Runnable() {
                        @Override
                        public void run() {
                            int nextInt = random.nextInt(10000);
                            if (nextInt < 1000) {
                                try {
                                    /*相當於有10%的概率暫停 5秒 模擬任務的執行耗時*/
                                    Thread.sleep(5000);
                                } catch (Exception e) {
                                }
                            } else if (nextInt < 3000) {
                                try {
                                    /*相當於有30%的概率暫停 2秒 模擬任務的執行耗時*/
                                    Thread.sleep(2000);
                                } catch (Exception e) {
                                }
                            } else if (nextInt < 5000) {
                                throw new UnsupportedOperationException("模擬拋錯異常");
                            }
                            log.error(System.currentTimeMillis());
                        }
                    });
                    /*通知線程有新任務了*/
                    synchronized (threadTest.runs) {
                        threadTest.runs.notify();
                    }
                }
            }
        });
        thread1.start();

修改一下線程添加任務的代碼模擬跑出異常

[01-20 15:49:08:0874:ERROR: sz.TestMain.run():95 ] -> 1484898548874
[01-20 15:49:08:0875:ERROR: sz.TestMain.run():46 ] -> 
java.lang.UnsupportedOperationException: 模擬拋錯異常
    at net.sz.TestMain$1$1.run(TestMain.java:93)
    at net.sz.ThreadTest.run(TestMain.java:42)
    at java.lang.Thread.run(Thread.java:745)
[01-20 15:49:09:0875:ERROR: sz.TestMain.run():46 ] -> 
java.lang.UnsupportedOperationException: 模擬拋錯異常
    at net.sz.TestMain$1$1.run(TestMain.java:93)
    at net.sz.ThreadTest.run(TestMain.java:42)
    at java.lang.Thread.run(Thread.java:745)
[01-20 15:49:11:0875:ERROR: sz.TestMain.run():46 ] -> 
java.lang.UnsupportedOperationException: 模擬拋錯異常
    at net.sz.TestMain$1$1.run(TestMain.java:93)
    at net.sz.ThreadTest.run(TestMain.java:42)
    at java.lang.Thread.run(Thread.java:745)
[01-20 15:49:13:0889:ERROR: sz.TestMain.main():117] -> 線程執行耗時:13
[01-20 15:49:14:0890:ERROR: sz.TestMain.main():115] -> 線程可能已卡死:1014
[01-20 15:49:15:0876:ERROR: sz.TestMain.run():95 ] -> 1484898555876
[01-20 15:49:15:0876:ERROR: sz.TestMain.run():95 ] -> 1484898555876

我們可以看出,當線程執行的時候拋出異常

其實這種異常,也不存在我那天,對不對,我們能try catch ,

並且可能童鞋都知道,java里面catch 的代碼塊如果沒有異常出現,是不會有性能消耗的,如果

拋出了異常,會創建 exception 對象,並且收集異常信息,比如調用堆棧,行號,文件名,路勁等等;

所以寫代碼的時候可以加入try catch 語句,放心一般不會影響你的性能;

來來接着

 

看到這里我們的線程也沒有出問題啊,而且,很安全啊

接下來我先不說情況,給各位模擬一下線程出問題的情況

也是一直困擾我很久的事情,曾經游戲服務器上線后一度出現線程卡死,很長時間,一直懷疑數據庫卡着不動!

 1 public class TestMain {
 2 
 3     private static final Logger log = Logger.getLogger(TestMain.class);
 4     static ThreadTest threadTest = new ThreadTest();
 5     static Thread thread;
 6     static Thread thread1;
 7 
 8     public static void main(String[] args) throws InterruptedException {
 9         /*創建線程任務隊列*/
10 
11         thread = new Thread(threadTest);
12         /*啟動線程*/
13         thread.start();
14         long i = 0;
15 
16         Random random = new Random();
17 
18         thread1 = new Thread(new Runnable() {
19             @Override
20             public void run() {
21                 while (true) {
22                     try {
23                         /*相當於沒 2秒 有一個任務需要處理*/
24                         Thread.sleep(2000);
25                     } catch (Exception e) {
26                     }
27                     /*創建任務*/
28                     threadTest.runs.add(new Runnable() {
29                         @Override
30                         public void run() {
31                             new TestRun();
32                             log.error(System.currentTimeMillis());
33                         }
34                     });
35                     /*通知線程有新任務了*/
36                     synchronized (threadTest.runs) {
37                         threadTest.runs.notify();
38                     }
39                 }
40             }
41         });
42         thread1.start();
43         while (true) {
44             try {
45                 /*相當於沒 1秒 檢查*/
46                 Thread.sleep(1000);
47             } catch (Exception e) {
48             }
49             long timer = System.currentTimeMillis() - threadTest.lastTimer;
50             if (threadTest.lastRun != null) {
51                 if (timer > 500) {
52                     showStackTrace();
53                 } else {
54                     log.error("線程執行耗時:" + timer + " " + threadTest.lastRun.getClass().getName());
55                 }
56             }
57         }
58     }
59 
60     /**
61      *
62      * 查看線程堆棧
63      */
64     public static void showStackTrace() {
65         StringBuilder buf = new StringBuilder();
66         /*如果現場意外終止*/
67         long procc = System.currentTimeMillis() - threadTest.lastTimer;
68         if (procc > 5 * 1000 && procc < 864000000L) {//小於10天//因為多線程操作時間可能不准確
69             buf.append("線程[")
70                     .append(thread.getName())
71                     .append("]")
72                     .append("可能已卡死 -> ")
73                     .append(procc / 1000f)
74                     .append("s\n    ")
75                     .append("執行任務:")
76                     .append(threadTest.lastRun.getClass().getName());
77             try {
78                 StackTraceElement[] elements = thread.getStackTrace();
79                 for (int i = 0; i < elements.length; i++) {
80                     buf.append("\n    ")
81                             .append(elements[i].getClassName())
82                             .append(".")
83                             .append(elements[i].getMethodName())
84                             .append("(").append(elements[i].getFileName())
85                             .append(";")
86                             .append(elements[i].getLineNumber()).append(")");
87                 }
88             } catch (Exception e) {
89                 buf.append(e);
90             }
91             buf.append("\n++++++++++++++++++++++++++++++++++");
92             String toString = buf.toString();
93             log.error(toString);
94         }
95     }
96 }

同樣先改造一下任務模擬線程;

這次我們直接new 一個對象;

並且我們增加如果判斷線程卡住的話打印線程堆棧情況

 1 [01-20 16:09:39:0787:ERROR: sz.TestMain.showStackTrace():149] -> 線程[Thread-0]可能已卡死 -> 8.008s
 2     執行任務:net.sz.TestMain$1$1
 3 ++++++++++++++++++++++++++++++++++
 4 [01-20 16:09:40:0787:ERROR: sz.TestMain.showStackTrace():149] -> 線程[Thread-0]可能已卡死 -> 9.008s
 5     執行任務:net.sz.TestMain$1$1
 6 ++++++++++++++++++++++++++++++++++
 7 [01-20 16:09:41:0787:ERROR: sz.TestMain.showStackTrace():149] -> 線程[Thread-0]可能已卡死 -> 10.008s
 8     執行任務:net.sz.TestMain$1$1
 9 ++++++++++++++++++++++++++++++++++
10 [01-20 16:09:42:0790:ERROR: sz.TestMain.showStackTrace():149] -> 線程[Thread-0]可能已卡死 -> 11.011s
11     執行任務:net.sz.TestMain$1$1
12 ++++++++++++++++++++++++++++++++++
13 [01-20 16:09:43:0791:ERROR: sz.TestMain.showStackTrace():149] -> 線程[Thread-0]可能已卡死 -> 12.012s
14     執行任務:net.sz.TestMain$1$1
15 ++++++++++++++++++++++++++++++++++
16 [01-20 16:09:44:0791:ERROR: sz.TestMain.showStackTrace():149] -> 線程[Thread-0]可能已卡死 -> 13.012s
17     執行任務:net.sz.TestMain$1$1
18 ++++++++++++++++++++++++++++++++++
19 [01-20 16:09:45:0792:ERROR: sz.TestMain.showStackTrace():149] -> 線程[Thread-0]可能已卡死 -> 14.013s
20     執行任務:net.sz.TestMain$1$1
21 ++++++++++++++++++++++++++++++++++

一般當玩家反映我們游戲出問題,以后ssh登錄服務器查看日志情況的時候滿篇基本都是這樣的情況;

看上去是線程執行某個任務的時候出現了卡住,當時線上游戲出現的是執行數據庫獲取玩家數據加載,然后卡住了,

當時一度懷疑,我們mysql數據庫不穩定,是不是數據庫問題,但是DBA很明確的告訴我們數據庫沒問題,連接量也很正常;服務很正常;

但是沒辦法,只能現在關閉服務器;

我們通常使用https的gm命令停止服務器,可是此時發現,使用http是的gm命令停止服務器依然沒有任何效果;;

當時已經瓜了,只能痛 kill 命令停止java進程,導致玩家回檔,有時間回檔幾分鍾,有時候回檔幾個小時;

玩家一度下滑;

那個時候非常的煎熬,因為不知道問題到底在哪里,看代碼無法反應出來;

於是,去排除最近新添加的所有代碼;看上去貌似有一個些不合理的代碼(有新手童鞋),改掉;

提交,編譯,上傳到服務器,啟動游戲;能夠正常運行;

一直都是這樣懷疑服務器邏輯問題;

錯誤日志

然后公司運維,在查詢服務器日志異常打印情況是給我反饋了一部分異常日志;

我這里展示我測試代碼的異常日志

 1 Exception in thread "Thread-0" java.lang.ExceptionInInitializerError
 2     at net.sz.TestMain$1$1.run(TestMain.java:87)
 3     at net.sz.ThreadTest.run(TestMain.java:47)
 4     at java.lang.Thread.run(Thread.java:745)
 5 Caused by: java.lang.UnsupportedOperationException
 6     at net.sz.TestRun.<clinit>(TestRun.java:18)
 7     ... 3 more
 8 [01-20 16:09:36:0782:ERROR: sz.TestMain.showStackTrace():149] -> 線程[Thread-0]可能已卡死 -> 5.001s
 9     執行任務:net.sz.TestMain$1$1
10 ++++++++++++++++++++++++++++++++++

看上去是有錯誤打印的,然后緊接着就出現了線程卡死情況;很奇怪明明有try catch 啊

現在我們再來看看,我們的TestRun 這個類的寫法

 1 package net.sz;
 2 
 3 import org.apache.log4j.Logger;
 4 
 5 /**
 6  *
 7  * <br>
 8  * author 失足程序員<br>
 9  * mail 492794628@qq.com<br>
10  * phone 13882122019<br>
11  */
12 public class TestRun {
13 
14     private static final Logger log = Logger.getLogger(TestRun.class);
15 
16     static {
17         if (true) {
18             throw new UnsupportedOperationException();
19         }
20     }
21 }

由於我是在模擬測試代碼,

所以直接在loader這個class的時候就init錯誤,拋出exception,然后一直以為這樣的exception是可以try catch 的,原諒我這么多年的小白鼠

PS:(當然,當時我游戲服務器出現的情況是hibernate和c3p0獲取socket 數據連接導致的;)

直到這兩天我在開發過程中發現這樣的異常情況,導致線程卡死,我就開始懷疑了,

當時一個偶發情況想到先去查看線程狀態;

於是在查看線程堆棧里面加入線程當前狀態;

 1     /**
 2      *
 3      * 查看線程堆棧
 4      */
 5     public static void showStackTrace() {
 6         StringBuilder buf = new StringBuilder();
 7         /*如果現場意外終止*/
 8         long procc = System.currentTimeMillis() - threadTest.lastTimer;
 9         if (procc > 5 * 1000 && procc < 864000000L) {//小於10天//因為多線程操作時間可能不准確
10             buf.append("線程[")
11                     .append(thread.getName())
12                     .append("]")
13                     .append("]當前狀態->")
14                     .append(thread.getState())
15                     .append("可能已卡死 -> ")
16                     .append(procc / 1000f)
17                     .append("s\n    ")
18                     .append("執行任務:")
19                     .append(threadTest.lastRun.getClass().getName());
20             try {
21                 StackTraceElement[] elements = thread.getStackTrace();
22                 for (int i = 0; i < elements.length; i++) {
23                     buf.append("\n    ")
24                             .append(elements[i].getClassName())
25                             .append(".")
26                             .append(elements[i].getMethodName())
27                             .append("(").append(elements[i].getFileName())
28                             .append(";")
29                             .append(elements[i].getLineNumber()).append(")");
30                 }
31             } catch (Exception e) {
32                 buf.append(e);
33             }
34             buf.append("\n++++++++++++++++++++++++++++++++++");
35             String toString = buf.toString();
36             log.error(toString);
37         }
38     }
View Code

 

Exception in thread "Thread-0" java.lang.ExceptionInInitializerError
    at net.sz.TestMain$1$1.run(TestMain.java:87)
    at net.sz.ThreadTest.run(TestMain.java:47)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.UnsupportedOperationException
    at net.sz.TestRun.<clinit>(TestRun.java:18)
    ... 3 more
[01-20 16:26:50:0593:ERROR: sz.TestMain.main():110] -> 線程執行耗時:1 net.sz.TestMain$1$1
[01-20 16:26:55:0599:ERROR: sz.TestMain.showStackTrace():151] -> 線程[Thread-0]]當前狀態->TERMINATED可能已卡死 -> 5.006s
    執行任務:net.sz.TestMain$1$1
++++++++++++++++++++++++++++++++++
[01-20 16:26:56:0600:ERROR: sz.TestMain.showStackTrace():151] -> 線程[Thread-0]]當前狀態->TERMINATED可能已卡死 -> 6.008s
    執行任務:net.sz.TestMain$1$1
++++++++++++++++++++++++++++++++++

好家伙,不看不知道猛一看嚇了我一條;

難怪線程卡死啊,線程當前狀態是線程已經結束退出執行了;

於是百度了一下,線程,java線程;

看到一篇文章,就是當java代碼拋出 jvm異常

1 Exception in thread "Thread-0" java.lang.ExceptionInInitializerError
2     at net.sz.TestMain$1$1.run(TestMain.java:87)
3     at net.sz.ThreadTest.run(TestMain.java:47)
4     at java.lang.Thread.run(Thread.java:745)
5 Caused by: java.lang.UnsupportedOperationException
6     at net.sz.TestRun.<clinit>(TestRun.java:18)
7     ... 3 more

類似這樣的異常的時候,是不會拋出來而是直接走

線程的

1 public interface UncaughtExceptionHandler

而是線程的這個接口的代碼;

如果你對線程是屬於線程組的,會調用線程組的

1     public UncaughtExceptionHandler getUncaughtExceptionHandler() {
2         return uncaughtExceptionHandler != null ?
3             uncaughtExceptionHandler : group;
4     }
1 void uncaughtException(Thread t, Throwable e)

如果線程實現了這個接口,或者是歸於線程組,走線程組的這個方法,拋錯異常,並且結束了當前線程;

哎,這就是基礎知識不扎實的我;導致了這個問題;

其實我們在做底層代碼或者框架設計的時候,能避免一些代碼和異常規范,但是不能保證沒人都能寫的很規范,或者基礎知識很扎實;

起碼我在這個事情之前也不算過關對吧;

線程狀態的監聽

百度的時候看到一個文章;

可以監聽線程狀態如果線程改變了就通知你,

大家可以看這個文章,我就不在贅述《Java線程監聽,意外退出線程后自動重啟》

線程修改結果,同時監聽線程

1 class MyThread extends Thread {
2 
3     Runnable run;
4 
5     public MyThread(Runnable run) {
6         super(run);
7         this.run = run;
8     }
9 }

我們新增一個mythread類;描述當前線程

 修改線程啟動方式

 1         /*創建線程任務隊列*/
 2         thread = new MyThread(threadTest);
 3 
 4         uncaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
 5             @Override
 6             public void uncaughtException(Thread t, Throwable e) {
 7                 log.error("收到未能正常捕獲的異常", e);
 8                 if (t instanceof MyThread) {
 9                     /*判斷是我們自定義線程模型,創建新的線程*/
10                     thread = new MyThread(((MyThread) t).run);
11                     thread.setUncaughtExceptionHandler(uncaughtExceptionHandler);
12                     /*啟動線程*/
13                     thread.start();
14                 }
15             }
16         };
17 
18         thread.setUncaughtExceptionHandler(uncaughtExceptionHandler);
19         /*啟動線程*/
20         thread.start();

並且修改一下模擬添加任務線程

 1 thread1 = new Thread(new Runnable() {
 2             @Override
 3             public void run() {
 4                 while (true) {
 5                     try {
 6                         /*相當於沒 2秒 有一個任務需要處理*/
 7                         Thread.sleep(2000);
 8                     } catch (Exception e) {
 9                     }
10                     /*任務隊列一直不能執行*/
11                     if (threadTest.runs.isEmpty()) {
12                         /*創建任務*/
13                         threadTest.runs.add(new Runnable() {
14                             @Override
15                             public void run() {
16                                 /*20%概率增加錯誤異常*/
17                                 if (random.nextInt(10000) < 2000) {
18                                     new TestRun();
19                                 }
20                                 log.error(System.currentTimeMillis());
21                             }
22                         });
23                         /*通知線程有新任務了*/
24                         synchronized (threadTest.runs) {
25                             threadTest.runs.notify();
26                         }
27                     }
28                 }
29             }
30         });
View Code
 1 --- exec-maven-plugin:1.2.1:exec (default-cli) @ net.sz.game.engine.thread ---
 2 [01-20 17:17:55:0419:ERROR: sz.TestMain.run():118] -> 1484903875419
 3 [01-20 17:17:57:0419:ERROR: sz.TestMain.run():118] -> 1484903877419
 4 [01-20 17:17:59:0419:ERROR: sz.TestMain.run():118] -> 1484903879419
 5 [01-20 17:18:01:0419:ERROR: sz.TestMain.run():118] -> 1484903881419
 6 [01-20 17:18:01:0420:ERROR: sz.TestMain.main():142] -> 線程執行耗時:1 net.sz.TestMain$2$1
 7 [01-20 17:18:03:0420:ERROR: sz.TestMain.run():118] -> 1484903883420
 8 [01-20 17:18:05:0420:ERROR: sz.TestMain.run():118] -> 1484903885420
 9 [01-20 17:18:07:0421:ERROR: sz.TestMain.run():118] -> 1484903887421
10 [01-20 17:18:09:0422:ERROR: sz.TestMain.uncaughtException():82 ] -> 收到未能正常捕獲的異常
11 java.lang.ExceptionInInitializerError
12     at net.sz.TestMain$2$1.run(TestMain.java:116)
13     at net.sz.ThreadTest.run(TestMain.java:47)
14     at java.lang.Thread.run(Thread.java:745)
15 Caused by: java.lang.UnsupportedOperationException
16     at net.sz.TestRun.<clinit>(TestRun.java:18)
17     ... 3 more
18 [01-20 17:18:11:0421:ERROR: sz.TestMain.run():118] -> 1484903891421
19 [01-20 17:18:13:0421:ERROR: sz.TestMain.uncaughtException():82 ] -> 收到未能正常捕獲的異常
20 java.lang.NoClassDefFoundError: Could not initialize class net.sz.TestRun
21     at net.sz.TestMain$2$1.run(TestMain.java:116)
22     at net.sz.ThreadTest.run(TestMain.java:47)
23     at java.lang.Thread.run(Thread.java:745)
24 [01-20 17:18:15:0421:ERROR: sz.TestMain.run():118] -> 1484903895421
25 [01-20 17:18:17:0422:ERROR: sz.TestMain.run():118] -> 1484903897422
26 [01-20 17:18:19:0422:ERROR: sz.TestMain.run():118] -> 1484903899422
27 [01-20 17:18:21:0423:ERROR: sz.TestMain.run():118] -> 1484903901423

好吧,到此為止,我們線程模型,起碼保證了,一定的穩健性,

在異常退出以后,線程能重新啟動運行,保證程序正常運轉;當然我們在收到消息的異常處理,可以加入通知消息,起碼知道哪里代碼會導致這樣的情況

多些各位看官,看到此處;

有什么不同意見,或者建議,歡迎樓下寶貴意見;

稍后我會整理放入我svn目錄,會更新,包含這些代碼底層代碼;

期待吧,騷年們;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM