1、昨天線上出了個問題:我們線上的一個爬蟲任務(wù)一直沒有執(zhí)行完畢,導(dǎo)致后面其他的任務(wù)跑的數(shù)據(jù)出錯。發(fā)現(xiàn)問題之后,立刻找運維幫忙dump線上機器的日志來看:

我們可以看到線程的狀態(tài)還是runnable,然后看下線程的是阻塞在了socketRead0,因為之前有遇到過類似的問題就是MySQL的查詢語句,從線程池中拿連接的時候沒有校驗連接的有效性導(dǎo)致拿不到連接,然MySQL的連接超時時間是默認的8小時。導(dǎo)致任務(wù)一個無效的線程,拿阻塞了8個小時才斷開連接,問題當(dāng)然是毀滅性的了。當(dāng)然缺少有效性的校驗和超時時間的設(shè)置是必要的,但是任務(wù)的監(jiān)控添加也是有必要的。這個后面在說。
今天發(fā)生的這個問題是由于DefaultHttpClient這個不推薦使用的客戶端引起的,具體我們項目中的代碼是這樣使用的:

問題就出在這句上面:get.setConfig(RequestConfig.custom().setConnectTimeout(Constant.TIMEOUT)
? ? ? ? ? ? ? ? .setSocketTimeout(Constant.TIMEOUT).build());//10秒鐘超時時間
這個超時時間的設(shè)置是不對的。我們跟著源碼進去,我這里貼出非重要的路徑:

當(dāng)我們跟著源碼到DefaultRequestDirector的exectue的方法的時候就差不多要切入正題了。下面咱們具體看看一個特別重要的方法tryConnect,他里面給我們會設(shè)置連接的超時時間等信息。


tryConnect是一個內(nèi)部方法,先檢查是否當(dāng)前連接是否是開啟的,沒有就會開啟,進入到這個open方法中。


可以看到連接是有的上一個方法返回的open屬性的值是false。那么就去開啟這個連接。結(jié)合上一步我們可以知道這個方法是需要設(shè)置超時時間等信息的。同事我們也可以看到poolEntry連接池中的信息,創(chuàng)建時間就是我Test啟動的時間,超時時間是個特別大的值。

開啟的時候最終會走到PlainSocketFactory:

你會發(fā)現(xiàn)他是從HttpParams params里面取值的。而不是我們代碼中設(shè)置的樣子。

到此問題找到了,具體的解決辦法有沒有呢,當(dāng)然有啊,而且還不只一個:
解決辦法:
1.用下面的這種方式設(shè)置參數(shù)就是OK的啦。因為她就是按照下面的方式取值的么。

2.第二種不用這個廢棄的方式了。這種方式呢大家猜也難能猜到了,她設(shè)置值的時候是直接加載的config,就是咱們構(gòu)造的這個socketConfig啦。大家有興趣就跟進源碼中去看看了。

debug源碼真的很爽。