<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    John Jiang

    a cup of Java, cheers!
    https://github.com/johnshajiang/blog

       :: 首頁 ::  :: 聯(lián)系 :: 聚合  :: 管理 ::
      131 隨筆 :: 1 文章 :: 530 評論 :: 0 Trackbacks
    Java并發(fā)基礎(chǔ)實踐--退出任務(wù)I
    計劃寫一個"Java并發(fā)基礎(chǔ)實踐"系列,算作本人對Java并發(fā)學(xué)習(xí)與實踐的簡單總結(jié)。本文是該系列的第一篇,介紹了退出并發(fā)任務(wù)的最簡單方法。(2013.09.25最后更新)

    在一個并發(fā)任務(wù)被啟動之后,不要期望它總是會執(zhí)行完成。由于時間限制,資源限制,用戶操作,甚至是任務(wù)中的異常(尤其是運行時異常),...都可能造成任務(wù)不能執(zhí)行完成。如何恰當(dāng)?shù)赝顺鋈蝿?wù)是一個很常見的問題,而且實現(xiàn)方法也不一而足。

    1. 任務(wù)
    創(chuàng)建一個并發(fā)任務(wù),遞歸地獲取指定目錄下的所有子目錄與文件的絕對路徑,最后再將這些路徑信息保存到一個文件中,如代碼清單1所示:
    清單1
    public class FileScanner implements Runnable {

        
    private File root = null;

        
    private List<String> filePaths = new ArrayList<String>();

        
    public FileScanner1(File root) {
            
    if (root == null || !root.exists() || !root.isDirectory()) {
                
    throw new IllegalArgumentException("root must be legal directory");
            }

            
    this.root = root;
        }

        @Override
        
    public void run() {
            travleFiles(root);
            
    try {
                saveFilePaths();
            } 
    catch (Exception e) {
                e.printStackTrace();
            }
        }

        
    private void travleFiles(File parent) {
            String filePath 
    = parent.getAbsolutePath();
            filePaths.add(filePath);

            
    if (parent.isDirectory()) {
                File[] children 
    = parent.listFiles();
                
    for (File child : children) {
                    travleFiles(child);
                }
            }
        }

        
    private void saveFilePaths() throws IOException {
            FileWriter fos 
    = new FileWriter(new File(root.getAbsoluteFile()
                    
    + File.separator + "filePaths.out"));
            
    for (String filePath : filePaths) {
                fos.write(filePath 
    + "\n");
            }
            fos.close();
        }
    }

    2. 停止線程
    有一個很直接,也很干脆的方式來停止線程,就是調(diào)用Thread.stop()方法,如代碼清單2所示:
    清單2
    public static void main(String[] args) throws Exception {
        FileScanner task 
    = new FileScanner(new File("C:"));
        Thread taskThread 
    = new Thread(task);
        taskThread.start();

        TimeUnit.SECONDS.sleep(
    1);
        taskThread.stop();
    }
    但是,地球人都知道Thread.stop()在很久很久之前就不推薦使用了。根據(jù)官方文檔的介紹,該方法存在著固有的不安全性。當(dāng)停止線程時,將會釋放該線程所占有的全部監(jiān)視鎖,這就會造成受這些鎖保護(hù)的對象的不一致性。在執(zhí)行清單2的應(yīng)用程序時,它的運行結(jié)果是不確定的。它可能會輸出一個文件,其中包含部分的被掃描過的目錄和文件。但它也很有可能什么也不輸出,因為在執(zhí)行FileWriter.write()的過程中,可能由于線程停止而造成了I/O異常,使得最終無法得到輸出文件。

    3. 可取消的任務(wù)
    另外一種十分常見的途徑是,在設(shè)計之初,我們就使任務(wù)是可被取消的。一般地,就是提供一個取消標(biāo)志或設(shè)定一個取消條件,一旦任務(wù)遇到該標(biāo)志或滿足了取消條件,就會結(jié)束任務(wù)的執(zhí)行。如代碼清單3所示:
    清單3
    public class FileScanner implements Runnable {

        
    private File root = null;

        
    private List<String> filePaths = new ArrayList<String>();

        
    private boolean cancel = false;

        
    public FileScanner(File root) {
            
        }

        @Override
        
    public void run() {
            
        }

        
    private void travleFiles(File parent) {
            
    if (cancel) {
                
    return;
            }

            String filePath 
    = parent.getAbsolutePath();
            filePaths.add(filePath);

            
    if (parent.isDirectory()) {
                File[] children 
    = parent.listFiles();
                
    for (File child : children) {
                    travleFiles(child);
                }
            }
        }

        
    private void saveFilePaths() throws IOException {
            
        }

        
    public void cancel() {
            cancel 
    = true;
        }
    }
    新的FileScanner實現(xiàn)提供一個cancel標(biāo)志,travleFiles()會遍歷新的文件之前檢測該標(biāo)志,若該標(biāo)志為true,則會立即返回。代碼清單4是使用新任務(wù)的應(yīng)用程序。
    清單4
    public static void main(String[] args) throws Exception {
        FileScanner task 
    = new FileScanner(new File("C:"));
        Thread taskThread 
    = new Thread(task);
        taskThread.start();

        TimeUnit.SECONDS.sleep(
    3);
        task.cancel();
    }
    但有些時候使用可取消的任務(wù),并不能快速地退出任務(wù)。因為任務(wù)在檢測取消標(biāo)志之前,可能正處于等待狀態(tài),甚至可能被阻塞著。對清單2中的FileScanner稍作修改,讓每次訪問新的文件之前先睡眠10秒鐘,如代碼清單5所示:
    清單5
    public class FileScanner implements Runnable {

        

        
    private void travleFiles(File parent) {
            
    try {
                TimeUnit.SECONDS.sleep(
    10);
            } 
    catch (InterruptedException e) {
                e.printStackTrace();
            }

            
    if (cancel) {
                
    return;
            }

            
        }

        
    private void saveFilePaths() throws IOException {
            
        }

        
    public void cancel() {
            cancel 
    = true;
        }
    }
    再執(zhí)行清單3中的應(yīng)用程序時,可能發(fā)現(xiàn)任務(wù)并沒有很快速的退出,而是又等待了大約7秒鐘才退出。如果在檢查cancel標(biāo)志之前要先獲取某個受鎖保護(hù)的資源,那么該任務(wù)就會被阻塞,并且無法確定何時能夠退出。對于這種情況,就需要使用中斷了。

    4. 中斷
    中斷是一種協(xié)作機(jī)制,它并不會真正地停止一個線程,而只是提醒線程需要被中斷,并將線程的中斷狀態(tài)設(shè)置為true。如果線程正在執(zhí)行一些可拋出InterruptedException的方法,如Thread.sleep(),Thread.join()和Object.wait(),那么當(dāng)線程被中斷時,上述方法就會拋出InterruptedException,并且中斷狀態(tài)會被重新設(shè)置為false。任務(wù)程序只要恰當(dāng)處理該異常,就可以正常地退出任務(wù)。對清單5再稍作修改,即,如果任務(wù)在睡眠時遇上了InterruptedException,那么就取消任務(wù)。如代碼清單6所示:
    清單6
    public class FileScanner implements Runnable {

        

        
    private void travleFiles(File parent) {
            
    try {
                TimeUnit.SECONDS.sleep(
    10);
            } 
    catch (InterruptedException e) {
                cancel();
            }

            
    if (cancel) {
                
    return;
            }

            
        }

        
    }
    同時將清單4中的應(yīng)用程序,此時將調(diào)用Thread.interrupt()方法去中斷線程,如代碼清單7所示:
    清單7
    public static void main(String[] args) throws Exception {
        FileScanner3 task 
    = new FileScanner3(new File("C:"));
        Thread taskThread 
    = new Thread(task);
        taskThread.start();

        TimeUnit.SECONDS.sleep(
    3);
        taskThread.interrupt();
    }
    或者更進(jìn)一步,僅使用中斷狀態(tài)來控制程序的退出,而不再使用可取消的任務(wù)(即,刪除cancel標(biāo)志),將清單6中的FileScanner修改成如下:
    清單8
    public class FileScanner implements Runnable {

        

        
    private void travleFiles(File parent) {
            
    try {
                TimeUnit.SECONDS.sleep(
    10);
            } 
    catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }

            
    if (Thread.currentThread().isInterrupted()) {
                
    return;
            }

            
        }

        
    }
    再次執(zhí)行清單7的應(yīng)用程序后,新的FileScanner也能即時的退出了。值得注意的是,因為當(dāng)sleep()方法拋出InterruptedException時,該線程的中斷狀態(tài)將又會被設(shè)置為false,所以必須要再次調(diào)用interrupt()方法來保存中斷狀態(tài),這樣在后面才可以利用中斷狀態(tài)來判定是否需要返回travleFiles()方法。當(dāng)然,對于此處的例子,在收到InterruptedException時也可以選擇直接返回,如代碼清單9所示:
    清單9
    public class FileScanner implements Runnable {

        

        
    private void travleFiles(File parent) {
            
    try {
                TimeUnit.SECONDS.sleep(
    10);
            } 
    catch (InterruptedException e) {
                
    return;
            }

            
        }

        
    }

    5 小結(jié)
    本文介紹了三種簡單的退出并發(fā)任務(wù)的方法:停止線程;使用可取消任務(wù);使用中斷。毫無疑問,停止線程是不可取的。使用可取消的任務(wù)時,要避免任務(wù)由于被阻塞而無法及時,甚至永遠(yuǎn)無法被取消。一般地,恰當(dāng)?shù)厥褂弥袛嗍侨∠蝿?wù)的首選方式。
    posted on 2013-09-21 19:11 John Jiang 閱讀(2037) 評論(0)  編輯  收藏 所屬分類: JavaSEJavaConcurrency原創(chuàng)Java并發(fā)基礎(chǔ)實踐
    主站蜘蛛池模板: 亚洲国产成人久久精品软件| 亚洲人成人77777网站不卡| 高潮毛片无遮挡高清免费视频| 99久久这里只精品国产免费 | 亚洲国产天堂久久综合| 亚洲欧美日韩中文高清www777 | 91麻豆国产免费观看| 一区二区三区亚洲| 亚洲免费观看网站| 亚洲国产日韩在线一区| 毛片免费视频观看| 精品国产日韩亚洲一区在线| 无码国产亚洲日韩国精品视频一区二区三区| 亚洲av成人无码网站…| 亚洲精品岛国片在线观看| 黄色短视频免费看| 亚洲视频.com| 成人免费视频软件网站| 日韩亚洲人成在线综合| 亚洲成人国产精品| 久久国产精品成人免费| 亚洲一卡2卡3卡4卡国产网站 | 在线看片v免费观看视频777| 亚洲欧美日韩中文二区| 亚洲一区二区三区无码影院| 免费看搞黄视频网站| avtt天堂网手机版亚洲| 又粗又大又长又爽免费视频| 中文字幕无线码免费人妻| 亚洲色图视频在线观看| 国产午夜无码视频免费网站| baoyu122.永久免费视频| 亚洲天堂一区二区三区| 免费a级毛片无码a∨性按摩| 国产精品免费无遮挡无码永久视频| 亚洲中文字幕久久精品无码2021| 国产人妖ts在线观看免费视频| 久久久久久免费一区二区三区 | 成人亚洲国产精品久久| 五月天网站亚洲小说| 国产在线19禁免费观看|