Java調(diào)用存儲(chǔ)過(guò)程長(zhǎng)時(shí)間未執(zhí)行完問(wèn)題-解決方案

上午在生產(chǎn)服務(wù)器發(fā)現(xiàn)一個(gè)不小的問(wèn)題炕檩,就是一個(gè)程序在調(diào)用存儲(chǔ)過(guò)程中搶到了鎖吁系,但搶到鎖后調(diào)用存儲(chǔ)過(guò)程執(zhí)行出現(xiàn)卡死的情況辕宏,導(dǎo)致?lián)尩降逆i遲遲沒(méi)有釋放,這導(dǎo)致第二天程序執(zhí)行時(shí)宇智,因?yàn)闊o(wú)法獲取到鎖而無(wú)法正常執(zhí)行蔓搞。

解決方案:引入Future類,并設(shè)定調(diào)用存儲(chǔ)過(guò)程執(zhí)行的超時(shí)時(shí)間普筹,通過(guò)get(long timeout, TimeUnit unit)败明,當(dāng)拋出超時(shí)異常時(shí),記錄異常太防,往下進(jìn)行其他處理邏輯妻顶,并正常釋放鎖。

當(dāng)創(chuàng)建了Future實(shí)例蜒车,任務(wù)可能有以下三種狀態(tài):

  • 等待狀態(tài)讳嘱。此時(shí)調(diào)用cancel()方法不管傳入true還是false都會(huì)標(biāo)記為取消,任務(wù)依然保存在任務(wù)隊(duì)列中酿愧,但當(dāng)輪到此任務(wù)運(yùn)行時(shí)會(huì)直接跳過(guò)沥潭。
  • 完成狀態(tài)。此時(shí)cancel()不會(huì)起任何作用嬉挡,因?yàn)槿蝿?wù)已經(jīng)完成了钝鸽。
  • 運(yùn)行中。此時(shí)傳入true會(huì)中斷正在執(zhí)行的任務(wù)庞钢,傳入false則不會(huì)中斷拔恰。

總結(jié):
Future.cancel(true)適用于:
(1) 長(zhǎng)時(shí)間處于運(yùn)行的任務(wù),并且能夠處理interruption

Future.cancel(false)適用于:
(1) 未能處理interruption的任務(wù) ;
(2) 不清楚任務(wù)是否支持取消 ;
(3) 需要等待已經(jīng)開(kāi)始的任務(wù)執(zhí)行完成

吊詭的事情:當(dāng)超時(shí)后基括,我調(diào)用Future的cancel(true)方法颜懊,在本地demo測(cè)試如下代碼時(shí),均可以正常中斷任務(wù)線程,但在Spring項(xiàng)目工程中使用時(shí)河爹,卻沒(méi)有實(shí)現(xiàn)效果匠璧。這個(gè)坑,暫且留下咸这,還待后面再補(bǔ)上夷恍。

回復(fù)吊詭的事情:這里把坑補(bǔ)上,其實(shí)吊詭的事情并不吊詭炊苫,主要是我事先沒(méi)有一個(gè)詞“能夠處理interruption”或是“可中斷的方法”裁厅。下面解釋一下:

當(dāng)一個(gè)方法內(nèi)部調(diào)用了wait、sleep侨艾、join等方法時(shí),會(huì)使得當(dāng)前線程進(jìn)入阻塞狀態(tài)拓挥,若另外的一個(gè)線程調(diào)用被阻塞線程的interrupt方法唠梨,則會(huì)打斷這種阻塞,因此這種方法有時(shí)會(huì)被稱為可中斷方法侥啤。記住当叭,打斷一個(gè)線程并不等于該線程的生命周期結(jié)束,僅僅是打斷了當(dāng)前線程的阻塞狀態(tài)盖灸。

而所謂“吊詭的事情”發(fā)生蚁鳖,正是因?yàn)槲以赿emo測(cè)試的代碼中調(diào)用sleep方法,使得demo測(cè)試的代碼成為了可中斷的方法赁炎,而Spring工程中的代碼醉箕,未調(diào)用sleep等類方法,也就是未進(jìn)入阻塞狀態(tài)徙垫,故而無(wú)法被中斷讥裤。

demo測(cè)試代碼


package com.xgh.demo.threaddemo;


import java.util.concurrent.*;

public class TestFuture {

    public static void main(String[] args) {

        try {
            testTimeout3(100);
            System.out.println("執(zhí)行結(jié)束3。姻报。己英。。");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    public static void testTimeout1(final int num) throws InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newScheduledThreadPool(5);
        Future result1 = executor.submit(new Callable() {
            @Override
            public Integer call() throws Exception {
                Thread.sleep(10000);
                System.out.println(num + "-22222222222222" + Thread.currentThread().getName());
                return num;
            }

        });
        System.out.println("下面開(kāi)始判斷程序是否超時(shí)或已經(jīng)執(zhí)行完畢吴旋。损肛。。");
        long currentTimeMillis = System.currentTimeMillis();

        long timeout = 5 * 1000L;
        while (!result1.isDone()) {
            long timecha = System.currentTimeMillis() - currentTimeMillis;
            if (timecha >= timeout) {
                System.out.println("revoke timeout");
                boolean cancel = result1.cancel(true);
                System.out.println("revoke cancel result : --->" + cancel + " ;result isCancelled: " + result1.isCancelled());
                cancel = result1.cancel(true);
                System.out.println("revoke cancel result2 : --->" + cancel + " ;result isCancelled: " + result1.isCancelled());
                break;
            }

            if (result1.isDone()) {
                System.out.println("result1----->" + result1.get());
                System.out.println("revoke success...");
                boolean cancel = result1.cancel(true);
                System.out.println("revoke cancel result : --->" + cancel);
                break;
            }
        }
        executor.shutdown(); //關(guān)閉線程池
    }

    public static void testTimeout2(final int num) throws InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newScheduledThreadPool(5);
        Future result1 = executor.submit(new Callable() {
            @Override
            public Boolean call() throws Exception {
                Thread.sleep(10000);
                System.out.println(num + "=========" + Thread.currentThread().getName());
                return true;
            }

        });
        long timeout = 5 * 1000L;
        try {
            boolean result = (boolean) result1.get(timeout, TimeUnit.MILLISECONDS);
            System.out.println("revoke success荣瑟,result ----->" + result);
        } catch (TimeoutException e) {
            System.out.println("revoke timeout:" + e);
            boolean cancel = result1.cancel(true);
            System.out.println("revoke cancel result : --->" + cancel + " ;result isCancelled: " + result1.isCancelled());
        }
        executor.shutdown();
    }

    /**
     * 驗(yàn)證不可中斷的方法
     * @param num
     * @throws InterruptedException
     * @throws ExecutionException
     */
    public static void testTimeout3(final int num) throws InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newScheduledThreadPool(5);
        Future result1 = executor.submit(new Callable() {
            @Override
            public Integer call() throws Exception {
                int i= 1;
                while (true){
                    System.out.println(num + "-22222222222222" + Thread.currentThread().getName()+"=="+Thread.currentThread().isInterrupted());
                    i ++;
                    if (i == 99999999){
                        break;
                    }
                }
                return num;
            }

        });
        System.out.println("下面開(kāi)始判斷程序是否超時(shí)或已經(jīng)執(zhí)行完畢治拿。。褂傀。");
        long currentTimeMillis = System.currentTimeMillis();

        long timeout = 2000L;
        while (!result1.isDone()) {
            long timecha = System.currentTimeMillis() - currentTimeMillis;
            if (timecha >= timeout) {
                System.out.println("revoke timeout");
                boolean cancel = result1.cancel(true);
                System.out.println("revoke cancel result : --->" + cancel + " ;result isCancelled: " + result1.isCancelled());
                cancel = result1.cancel(true);
                System.out.println("revoke cancel result2 : --->" + cancel + " ;result isCancelled: " + result1.isCancelled());
                break;
            }

            if (result1.isDone()) {
                System.out.println("result1----->" + result1.get());
                System.out.println("revoke success...");
                boolean cancel = result1.cancel(true);
                System.out.println("revoke cancel result : --->" + cancel);
                break;
            }
        }
        executor.shutdown(); //關(guān)閉線程池
    }
}



參考文章:
https://felord.blog.csdn.net/article/details/104788189
https://blog.csdn.net/u014252478/article/details/82109694
https://blog.csdn.net/qq_24630433/article/details/88537407

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末忍啤,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌同波,老刑警劉巖鳄梅,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異未檩,居然都是意外死亡戴尸,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門冤狡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)孙蒙,“玉大人,你說(shuō)我怎么就攤上這事悲雳】媛停” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵合瓢,是天一觀的道長(zhǎng)坦胶。 經(jīng)常有香客問(wèn)我,道長(zhǎng)晴楔,這世上最難降的妖魔是什么顿苇? 我笑而不...
    開(kāi)封第一講書人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮税弃,結(jié)果婚禮上纪岁,老公的妹妹穿的比我還像新娘。我一直安慰自己则果,他們只是感情好幔翰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著短条,像睡著了一般导匣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上茸时,一...
    開(kāi)封第一講書人閱讀 51,208評(píng)論 1 299
  • 那天贡定,我揣著相機(jī)與錄音,去河邊找鬼可都。 笑死缓待,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的渠牲。 我是一名探鬼主播旋炒,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼签杈!你這毒婦竟也來(lái)了瘫镇?” 一聲冷哼從身側(cè)響起鼎兽,我...
    開(kāi)封第一講書人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎铣除,沒(méi)想到半個(gè)月后谚咬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡尚粘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年择卦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片郎嫁。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡秉继,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出泽铛,到底是詐尸還是另有隱情尚辑,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布厚宰,位于F島的核電站腌巾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏铲觉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一吓坚、第九天 我趴在偏房一處隱蔽的房頂上張望撵幽。 院中可真熱鬧,春花似錦礁击、人聲如沸盐杂。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)链烈。三九已至,卻和暖如春挚躯,著一層夾襖步出監(jiān)牢的瞬間强衡,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工码荔, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留漩勤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓缩搅,卻偏偏與公主長(zhǎng)得像越败,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子硼瓣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容