Java中用synchronized实现日志同步需区分静态与实例场景:静态同步方法锁Logger.class,适合简单控制台;实例级推荐私有final锁对象,避免死锁;须确保每条日志一次性完整输出,禁用多行println;生产环境应优先选用Log4j2等专业框架。

在 Java 中,用 synchronized 实现多线程同步打印日志,核心是确保多个线程对共享的日志输出操作(如调用 System.out.println 或写入文件)互斥执行,避免输出内容交错、乱序或损坏。
用 synchronized 修饰静态方法统一输出
适合简单控制台日志场景。将日志打印封装为一个 静态同步方法,所有线程共用同一把类锁:
public class Logger {
public static synchronized void log(String msg) {
System.out.println(Thread.currentThread().getName() + " - " + msg);
}
}调用时直接使用 Logger.log("任务开始")。由于是 static synchronized,锁的是 Logger.class,能保证任意时刻只有一个线程进入该方法。
用 synchronized(this) 或 synchronized 锁对象控制实例级日志
如果日志器是单例或需复用实例(比如带缓冲、格式化逻辑),推荐用私有锁对象,更安全、更可控:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
public class SafeLogger {
private final Object lock = new Object();
<pre class="brush:php;toolbar:false;">public void log(String msg) {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " - " + msg);
}
}}
- 避免直接锁
this,防止外部误同步导致死锁或性能瓶颈 - 锁对象
lock私有且 final,语义清晰、不可篡改 - 多个线程调用同一个
SafeLogger实例的log()方法时,自然串行化输出
注意:synchronized 只保输出原子性,不保日志内容完整性
即使加了同步,若日志内容本身跨多行或含多次 println,仍可能被其他线程插入。例如:
// ❌ 危险:两行打印不构成原子操作
synchronized (lock) {
System.out.print("用户 ");
System.out.println("登录成功"); // 可能被另一线程的 print 插入中间
}✅ 正确做法:每次日志拼成完整字符串,一次输出:
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " - 用户登录成功");
}补充建议:生产环境慎用 System.out.println
-
System.out是带缓冲的同步流,本身已有同步开销;高并发下会成为性能瓶颈 - 建议使用 Log4j2、SLF4J + Logback 等专业日志框架,它们内部已做异步、缓冲、锁优化
- 若必须手写,可配合
StringBuilder预拼接、减少 I/O 调用次数
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










