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);
            }
        }
    }
相关文章
相关标签/搜索