花了至少一整天的時間解決了這個問題,必須記錄這個糾結的過程,問題不可怕,思路很繞彎。
為了能說清楚自己的問題,我都用例子來模擬。
我有一個類MyThread是這樣的:
1 @Service 2 public class MyThread extends Thread {
3 @Autowired
4 MyService myService;
5 ......
6 }
在主線程中有這樣一個調用:
1 @Autowired 2 MyThread myThread; 3 ...... 4 public void invoke{ 5 if(condition){ 6 myThread.start(); 7 } 8 } 9 ......
我的invoke存在一個循環調用,此時遇到了第一個問題!
問題一:拋出java.lang.IllegalThreadStateException。
問題一的解決:
1 //@Autowired 2 //MyThread myThread; 3 ...... 4 public void invoke { 5 if(condition){
6 //myThread.start(); 6 MyThread myThread = new MyThread(); 7 myThread.start(); 8 } 9 }
引發的新的問題!
問題二:我用了Spring注解,用new的話無法用注解實現注入,所以myThread中的myService對象拋出空指針。
問題二的解決:放棄了MyThread類,新寫了一個類,開始繞彎。
1 @Service 2 public class MyRunable implements Runnable { 3 @Autowired 4 MyService myService; 5 ...... 6 }
相應的,修改主線程中的調用。
1 //@Autowired 2 //MyThread myThread; 3 @Autowired 4 MyRunnable myRunnable; 5 ...... 6 public void invoke{ 7 if(condition){ 8 //MyThread myThread = new MyThread(); 9 //myThread.start(); 10 Thread t = new Thread(myRunnable); 11 t.start(); 12 } 13 } 14 ......
又遇到了新的問題!
我需要對myRunnable線程命名。即在invoke方法中增加這么一行:
1 ...... 2 myRunnable.setName(name);//增加的一行 3 Thread t = new Thread(myRunnable); 4 ......
問題三:后面命名的myRunnable線程名稱竟然覆蓋前面的命名。
打印myRunnable對象,很容易判斷出來這個對象是單例模式,所以每次改動都會影響以前的調用。
查了Spring的相關資料,得到結論,Spring默認管理類的模式就是“單例模式”,我需要改成非單例的。
嘗試改動一:
1 //增加了對象使用創建模式的注解 2 @Service 3 @Scope("prototype") 4 public class MyRunable implements Runnable { 5 @Autowired 6 MyService myService; 7 ...... 8 }
運行,問題依舊。然后就卡住了,甚至評估放棄Spring?一路new下去得了……
直到某一刻靈光閃現,發現雖然現在MyRunnble是非單例模式,但是在invoke的那個類中,Spring只在加載這個類時初始化了一個MyRunnable對象啊……
問題三的解決:
1 //@Autowired 2 //MyThread myThread; 3 //@Autowired 4 //MyRunnable myRunnable; 5 ...... 6 public void invoke{ 7 if(condition){ 8 //MyThread myThread = new MyThread(); 9 //myThread.start(); 10 MyRunnable myRunnable = SpringContextUtil.getApplicationContext().getBean("myRunnable",MyRunnable.class); 11 Thread t = new Thread(myRunnable); 12 t.start(); 13 } 14 } 15 ......
這一步需要聲明的是SpringContextUtil類有時間需要單獨寫一篇,先理解原理,就是每次從Spring容器中生成一個全新[scope("prototype")]的對象。
到這里,問題全部解決了……等等!
感覺MyThread類被拋棄好無辜啊!最終改成了這個樣子的:
1 MyThread myThread = SpringContextUtil.getApplicationContext().getBean("myThread", MyThread.class);