我正在使用VanillaChronicle将一些消息写入磁盘。
public final class ConcurrentPersister{
private final String location;
private final Chronicle chronicle;
private final ExcerptAppender writer;
private final static int STRING_SIZE_OVERHEAD = 1000;
private final static String FILE_DATE_FORMAT = "MM-dd-yyyy";
private final static String NAME = "ConcurrentPersister";
private final static Logger LOGGER = LoggerFactory.getLogger( NAME );
public ConcurrentPersister( String location, VanillaChronicleConfig config ){
this.chronicle = new VanillaChronicle( location );
this.writer = chronicle.createAppender();
}
public final void appendMessage( final String message ){
try{
long length = STRING_SIZE_OVERHEAD + message.length();
writer.startExcerpt( length );
writer.append( message );
writer.finish();
}catch( Exception e ){
LOGGER.warn("Failed to persist Message [{}]", message );
LOGGER.warn("Exception: ", e );
}
}
}
如上所示,appendMessage(String message)方法是否是从多个线程调用的线程安全的?
我在某地读过VanillaChronicle的追加(字符串消息)是线程安全的。 但是,我认为startExcerpt()+ append()+ finish()的复合动作不是线程安全的吗?
感谢。
答案 0 :(得分:3)
VanillaChronicle有一个appenders / tailers的ThreadLocal缓存:
public VanillaAppender createAppender() throws IOException {
WeakReference<VanillaAppender> ref = appenderCache.get();
VanillaAppender appender = null;
if (ref != null)
appender = ref.get();
if (appender == null) {
appender = createAppender0();
appenderCache.set(new WeakReference<VanillaAppender>(appender));
}
return appender;
}
如果你没有数千个短生命线程,你可以在appendMessage方法中使用createAppender
public final void appendMessage( final String message ) {
try {
ExcerptAppender writer = chronicle.createAppender();
writer.startExcerpt( STRING_SIZE_OVERHEAD + message.length() );
writer.append( message );
writer.finish();
} catch( Exception e ) {
LOGGER.warn("Failed to persist Message [{}]", message );
LOGGER.warn("Exception: ", e );
}
}
我在某地读过VanillaChronicle的
append(String message)
是线程安全的。但是,我是否认为startExcerpt()
+append()
+finish()
的复合行为不是线程安全的?
VanillaChronicle可以由并发线程使用,即使是并发进程,只要每个线程使用它自己的appender。
答案 1 :(得分:0)
您需要在这三个方法调用上同步编写器。 append( message );
可能是线程安全的,但正如你所说,如果多个线程通过同一个ConcurrentPersister实例访问该方法,那么对writer的三个单独方法调用可能会发生冲突。
public final class ConcurrentPersister{
private final String location;
private final Chronicle chronicle;
private final ExcerptAppender writer;
private final static int STRING_SIZE_OVERHEAD = 1000;
private final static String FILE_DATE_FORMAT = "MM-dd-yyyy";
private final static String NAME = "ConcurrentPersister";
private final static Logger LOGGER = LoggerFactory.getLogger( NAME );
public ConcurrentPersister( String location, VanillaChronicleConfig config ){
this.chronicle = new VanillaChronicle( location );
this.writer = chronicle.createAppender();
}
public final void appendMessage( final String message ){
try{
long length = STRING_SIZE_OVERHEAD + message.length();
synchronized(writer){
writer.startExcerpt( length );
writer.append( message );
writer.finish();
}
}catch( Exception e ){
LOGGER.warn("Failed to persist Message [{}]", message );
LOGGER.warn("Exception: ", e );
}
}
}
根据您对此类的其他操作,可能更容易同步整个方法。
public synchronized final void appendMessage( final String message ){
但这会在ConcurrentPersister的实例上同步,而不是编写器。