java Future接口在logback的妙用

logback能夠把N天的日誌壓縮成一個包(zip,gz),在壓縮的時候logback採用後臺異步線程的方式來實現,下面我們就來看看Future接口在logback中的妙用。java

先來看下Future接口的全貌吧。異步

public interface Future<V> {

    //取消任務
    boolean cancel(boolean mayInterruptIfRunning);

    // 任務若是被取消就返回true
    boolean isCancelled();

     //若是任務完成就返回true
    boolean isDone();
     // 獲取線程的執行結果,若是任務沒有執行完成就會一直等待
    V get() throws InterruptedException, ExecutionException;

      //獲取任務的執行結果,能夠指定一個單位時間,若是在規定的時間內沒有完成任務,那麼就會拋出TimeoutException異常
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
/**
    gz壓縮方法,用於壓縮成.gz文件
*/
 private void gzCompress(String nameOfFile2gz, String nameOfgzedFile) {
        File file2gz = new File(nameOfFile2gz);

        if (!file2gz.exists()) {
            addStatus(new WarnStatus("The file to compress named [" + nameOfFile2gz + "] does not exist.", this));

            return;
        }

        if (!nameOfgzedFile.endsWith(".gz")) {
            nameOfgzedFile = nameOfgzedFile + ".gz";
        }

        File gzedFile = new File(nameOfgzedFile);

        if (gzedFile.exists()) {
            addWarn("The target compressed file named [" + nameOfgzedFile + "] exist already. Aborting file compression.");
            return;
        }

        addInfo("GZ compressing [" + file2gz + "] as [" + gzedFile + "]");
        createMissingTargetDirsIfNecessary(gzedFile);

        BufferedInputStream bis = null;
        GZIPOutputStream gzos = null;
        try {
            bis = new BufferedInputStream(new FileInputStream(nameOfFile2gz));
            gzos = new GZIPOutputStream(new FileOutputStream(nameOfgzedFile));
            byte[] inbuf = new byte[BUFFER_SIZE];
            int n;

            while ((n = bis.read(inbuf)) != -1) {
                gzos.write(inbuf, 0, n);
            }

            bis.close();
            bis = null;
            gzos.close();
            gzos = null;

            if (!file2gz.delete()) {
                addStatus(new WarnStatus("Could not delete [" + nameOfFile2gz + "].", this));
            }
        } catch (Exception e) {
            addStatus(new ErrorStatus("Error occurred while compressing [" + nameOfFile2gz + "] into [" + nameOfgzedFile + "].", this, e));
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    // ignore
                }
            }
            if (gzos != null) {
                try {
                    gzos.close();
                } catch (IOException e) {
                    // ignore
                }
            }
        }
    }


     //工廠方法,能夠根據傳入的類型來判斷是使用gz,仍是zip壓縮
    public void compress(String nameOfFile2Compress, String nameOfCompressedFile, String innerEntryName) {
        switch (compressionMode) {
        case GZ:
            gzCompress(nameOfFile2Compress, nameOfCompressedFile);
            break;
        case ZIP:
            zipCompress(nameOfFile2Compress, nameOfCompressedFile, innerEntryName);
            break;
        case NONE:
            throw new UnsupportedOperationException("compress method called in NONE compression mode");
        }
    }

logback 把壓縮的任務交給了一個線程去執行async

//開啓一個線程用於壓縮日誌文件
    public Future<?> asyncCompress(String nameOfFile2Compress, String nameOfCompressedFile, String innerEntryName) throws RolloverFailure {
        CompressionRunnable runnable = new CompressionRunnable(nameOfFile2Compress, nameOfCompressedFile, innerEntryName);
        ExecutorService executorService = context.getExecutorService();
        Future<?> future = executorService.submit(runnable);
        return future;
    }

 //壓縮線程
    class CompressionRunnable implements Runnable {
        final String nameOfFile2Compress;
        final String nameOfCompressedFile;
        final String innerEntryName;

        public CompressionRunnable(String nameOfFile2Compress, String nameOfCompressedFile, String innerEntryName) {
            this.nameOfFile2Compress = nameOfFile2Compress;
            this.nameOfCompressedFile = nameOfCompressedFile;
            this.innerEntryName = innerEntryName;
        }

        public void run() {
            Compressor.this.compress(nameOfFile2Compress, nameOfCompressedFile, innerEntryName);
        }
    }

stop方法纔是重頭戲,當調用stop方法的時候,須要檢查有沒有線程在正在進行壓縮工做,能夠看出logback使用Future的特性就是檢測某個後臺任務是否在指定時間內完成任務。ide

@Override
    public void stop() {
        if (!isStarted())
            return;
        //檢查任務是否完成
        //壓縮任務
        waitForAsynchronousJobToStop(compressionFuture, "compression");
        //clean任務
        waitForAsynchronousJobToStop(cleanUpFuture, "clean-up");
        super.stop();
    }

    private void waitForAsynchronousJobToStop(Future<?> aFuture, String jobDescription) {
        if (aFuture != null) {
            try {
              //獲取執行結果
                aFuture.get(CoreConstants.SECONDS_TO_WAIT_FOR_COMPRESSION_JOBS, TimeUnit.SECONDS);
            } catch (TimeoutException e) {
                addError("Timeout while waiting for " + jobDescription + " job to finish", e);
            } catch (Exception e) {
                addError("Unexpected exception while waiting for " + jobDescription + " job to finish", e);
            }
        }
    }
相關文章
相關標籤/搜索