2

我正在使用 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 的 append(String message) 是线程安全的。但是,我认为 startExcerpt() + append() + finish() 的复合动作不是线程安全的,这是否正确?

谢谢。

4

2 回答 2

3

VanillaChronicle 有一个 ThreadLocal 缓存的 appenders/tailers:

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 );
    }
}

我在某处读到 VanillaChronicleappend(String message)是线程安全的。但是,我认为startExcerpt()++的复合append()动作finish()不是线程安全的是否正确?

VanillaChronicle 可以被并发线程甚至并发进程使用,前提是每个线程都使用它自己的 appender。

于 2014-05-13T15:39:19.020 回答
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 的实例上同步,而不是在 writer 上同步。

于 2014-05-12T19:13:16.647 回答