Java同步性能

Java同步性能,java,multithreading,synchronization,locking,readwritelock,Java,Multithreading,Synchronization,Locking,Readwritelock,我想就此发表意见,以解决一个小争端。任何帮助都将不胜感激 我已经编写了自己的文件处理程序,该处理程序附加到记录器。这是一个文件处理程序,由多个线程访问,我使用同步来确保在编写过程中没有冲突。此外,它是一个滚动日志,所以我也关闭和打开文件,也不希望出现任何问题 他的回复是(从电子邮件中粘贴) 我坚信处理程序中的同步非常糟糕。信息技术 对于这样简单的任务来说,它太复杂了。所以,我想说,为什么不使用一个呢 每个线程的实例数 从性能和内存管理的角度来看,您认为什么更好。 非常感谢您的回复。每当在多线程应

我想就此发表意见,以解决一个小争端。任何帮助都将不胜感激

我已经编写了自己的文件处理程序,该处理程序附加到记录器。这是一个文件处理程序,由多个线程访问,我使用同步来确保在编写过程中没有冲突。此外,它是一个滚动日志,所以我也关闭和打开文件,也不希望出现任何问题

他的回复是(从电子邮件中粘贴)

我坚信处理程序中的同步非常糟糕。信息技术 对于这样简单的任务来说,它太复杂了。所以,我想说,为什么不使用一个呢 每个线程的实例数

从性能和内存管理的角度来看,您认为什么更好。 非常感谢您的回复。每当在多线程应用程序中涉及到写和读时,我一生都在java应用程序上使用同步,并且没有听说过任何严重的性能问题

所以,我想知道是否有任何问题,我真的应该切换到每个线程一个实例

一般来说,使用同步会有什么失败


编辑:我之所以编写自定义文件处理程序(是的,我非常喜欢slf4j),是因为我的自定义处理程序一次处理两个文件,而且除了写入文件之外,我几乎没有执行其他功能。

同步失败的原因是,在任何时候只有一个线程可以访问该部分代码,这意味着您的代码将看不到多线程的好处,即应用程序的同步部分将只与单个线程一样快。(处理同步状态的开销也很小,因此可能会稍微慢一点)


但是,在您不希望线程相互干扰的主题中,例如写入文件,从同步中获得的安全性是最重要的,性能损失应该被接受。

另一种解决方案是使用单独的线程来完成(成本高昂)写入并使用并发队列从域线程传递日志消息

这里的关键部分是,推送到队列的成本要比写入文件的成本低得多,这意味着并发日志调用的干扰更少

然后,对log的调用将类似于

private static BlockingQueue logQueue = //...

public static void log(String message){
//construct&filter message
    logQueue.add(message);
}
然后在记录器线程中

while(true){
    String message = logQueue.poll();
    logFile.println(message);//or whatever you are doing
}

与所有I/O一样,除了互斥之外,您别无选择。从理论上讲,您可能会建立一个复杂的方案,其中包含一个无锁队列,该队列会累积日志记录条目,但其实用性,尤其是其可靠性,将非常值得怀疑:如果不仔细设计,您可能会得到一个由日志记录引起的OOME,由于未清理的线程而导致应用程序挂起,等等


请记住,假设您使用的是缓冲I/O,那么您已经有了一个相当于队列的队列,从而最大限度地减少了占用锁的时间。

理论讨论是可以的(理论上(原文如此))。但是要定量地回答这个问题,您必须测试性能(您可以使用它)。同步确实会对性能产生影响—其严重程度取决于线程之间对受保护资源的争用。我不理解“每个线程一个实例”,这是否意味着每个处理程序都有一个单独的文件?当log4j、slf4j和apachecommons日志都存在时,为什么要这样做?日志记录问题还没有解决吗?为什么要浪费时间来改进已经做了很多次的工作呢?我怀疑任何应用程序都不会在日志记录上花费大量的运行时间——因此,除了拥有可靠的解决方案之外,性能可能根本不值得考虑。我非常怀疑这是一个瓶颈。@earcam我猜他的意思是为每个线程创建一个处理程序,这样他们就不会干扰。他的解释还在后面,但我也不理解。@Pescis日志记录实际上常常是一种现实生活中的性能威胁,但它也可以通过日志记录级别过滤器系统地控制。为什么“无锁”?正如@ratchetfreak所建议的,将日志条目对象排队到挂有日志写入线程的生产者消费者队列中不应该存在可靠性问题。这不是“精心设计”——它相当简单。@martin与缓冲IO相比会有什么好处?@martin与单个同步关键字相比,几乎没有任何东西可以被证明是“微不足道的”。+1=迄今为止最好的回答。将日志请求对象指针推到队列上的锁循环要比在每个需要记录日志的线程之间闲逛以获取互斥量要好得多。LogRequestClass+BlockingQueue+logger线程是一个很好的解决方案。可以避免实际磁盘写入的同步-请参阅@ratchet freak。