java 并发 写日志_Java并发编程(六) 一个日志服务的例子

日志服务需要提供的功能有:

可以从外部安全地开启和关闭日志服务;

可以供多个线程安全地记录日志消息;

在日志服务关闭后,可以把剩余未记录的消息写入日志文件;

public classLogService

{private final BlockingQueuemsgQueue; //阻塞的消息队列保存日志消息private finalPrintWrite writer; //写消息到日志文件private finalLoggerThread logThread; //写日志的线程private booleanisShutdown; //表示日志服务是否已经关闭publicLogService(String file) throws FileNotFoundException

{

logThread= newLogThread();

writer = new PrintWrite(file);

}public voidstart()

{

logThread.start(); //启动日志线程

Runtime.getRuntime().addShutdownHook(newThread() { //添加关闭钩子,确保在没有调用stop方法的情况下,日志文件最终仍然会关闭

stop();

});

}public voidstop()

{synchronized(this) //需要先加锁,再修改isShutdown的值

{if(!isShutdown)

{

isShutdown= true;

logThread.interrupt(); //中断日志线程

}

}

}public voidlog(String message)

{synchronized(this) //需要先加锁,再访问isShutdown的值

{if(!isShutdown) //若日志服务没有关闭,则将消息加入消息队列,这里是典型的先验条件,声明isShutdown为volatile并不能解决同步的问题

msgQueue.put(message);else

throw new IllegalStateException("Log Service is shutdown"); //若日志服务已经关闭,则抛出IllegalStateException

}

}private class LoggerThread extendsThread

{public voidrun()

{try{while(true)

{try{synchronized(LogService.this)

{if(isShutdown && msgQueue.size() == 0) //如果服务已经关闭并且消息队列中已经没有剩余的消息,则关闭日志线程break;

writer.write(msgQueue.take());

}

}catch(InterruptedException ex){} //忽略中断消息

}

}finally{

writer.close(); //关闭日志文件

}

}

}

}

在上面的例子中,有以下几个地方值得注意:

日志服务不应该在收到关闭消息时立即停止,而应该将消息队列中剩余的消息写入到日志文件之后再关闭。如果决定丢弃这些消息,那么应该先清空消息队列,否则调用log方法的线程会一直阻塞;

上例中使用isShutdown来标识服务是否已经关闭,调用log方法的线程首先检测isShutdown的值,这样多个线程就需要对isShutdown互斥访问,而不能简单使用volatile修饰isShutdown;

在日志线程中,检测到中断消息后,直接忽略了,最后在finally中也没有再恢复中断状态,这是因为我们知道线程的所有者日志服务已经停止了,不再需要恢复中断;

上例中使用了关闭钩子,在start方法中添加了关闭钩子线程,可以确保即使调用者没有调用stop方法停止日志服务,日志服务最终在JVM停止之前也会关闭;

下面简单介绍一下关闭钩子:

关闭钩子是通过Runtime.addShutdown方法注册的但并不立刻启动任务的线程,JVM在关闭过程中,首先会启动执行已经注册的关闭钩子线程。关闭钩子通常用于实现服务或者应用程序的清理工作,并且不宜在其中执行耗时的任务,会延迟JVM关闭的时间。

参考资料 《Java并发编程实战》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值