package canceltask; import java.io.PrintWriter; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; /** * 服务发挥是实际作用,需要终止日志线程,防止JVM无法正常关闭 * 3种方式终止运行中的线程 * 1.使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。 * 2.使用stop方法强行终止,但是不推荐这个方法,因为stop和suspend及resume一样都是过期作废的方法。 * 3.使用interrupt方法中断线程。 * 目前是生产者,消费者模式 * 消费者:在线程LoggerThread中可以响应中断(take方法),此时将日志线程修改为捕获到中断异常时退出即可。 * 但是会丢失队列中未被消费的数据,以及log方法阻塞,所以,需要同时中断生产者&消费者 * 所以在put操作时需要“先判断载运行,会产生竞态条件”,所以需要保证原子操作去检查关闭请求,并且递增一个计数器保持提交信息的权力。 * */ public class LogService { private LoggerThread loggerThread; private BlockingQueue blockingQueue; private int reservation; private boolean isShutDown; public LogService (PrintWriter printWriter) { blockingQueue = new LinkedBlockingQueue(); loggerThread = new LoggerThread(printWriter); } // 消费者 public void start () { loggerThread.start(); } public void stop () { synchronized (LogService.this) { isShutDown = true; } loggerThread.interrupt(); } // 生产者 public void log (String msg) throws IllegalAccessException, InterruptedException { synchronized (LogService.this) { if (isShutDown) { throw new IllegalAccessException(""); } reservation ++; } blockingQueue.put(msg); } private class LoggerThread extends Thread { PrintWriter printWriter; public LoggerThread (PrintWriter printWriter) { this.printWriter = printWriter; } @Override public void run() { while (true) { synchronized (LogService.this) { if (isShutDown && reservation == 0) { reservation --; } try { String msg = (String) blockingQueue.take(); printWriter.write(msg); } catch (InterruptedException e) { e.printStackTrace(); } finally { printWriter.close(); } } } } } }