You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何JRuby线程内调用puts有时不会在字符串末尾添加换行?

JRuby多线程下puts输出丢失换行的问题分析与解决

问题现象

在Ruby中,puts默认会在输出字符串末尾添加换行符,但在JRuby的多线程场景下,出现了异常行为:部分puts输出的换行符丢失,导致两行内容被打印在同一行。

复现代码如下:

def work(n)
  puts "Started unit of work ##{n}."
  i = 0
  100000000.times { i += 1 }
  puts "Finished unit of work ##{n}."
end

threads = []

2.times do |i|
  thread = Thread.new do
    work(i + 1)
  end
  threads << thread
end

threads.each do |t|
  t.join
end

puts "\nEnd."

运行后输出:

Started unit of work #1.Started unit of work #2.

Finished unit of work #2.
Finished unit of work #1.

End.

可以看到,两个线程中第一次调用puts的内容被拼接在同一行,而第二次调用puts的内容则正常分行。每次运行该脚本都会出现一致的异常结果。

系统环境信息:

  • JRuby版本:jruby 9.3.8.0 (2.6.8) 2022-09-13 98d69c9461 OpenJDK 64-Bit Server VM 19+36-2238 on 19+36-2238 +jit [x86_64-linux]
  • Java版本:openjdk 19 2022-09-20
  • 系统:Ubuntu 22.04.1 LTS

原因分析

JRuby的puts底层依赖Java的IO实现,而Java的System.out相关输出操作并非完全原子:puts的逻辑是先输出字符串,再输出换行符,这两步在多线程并发时可能被打断。当两个线程几乎同时执行puts时,线程A刚输出完字符串,线程B就开始输出自己的字符串,导致两个字符串拼接在一起,换行符被延后输出。

示例中第二次puts未出现问题,是因为中间的100000000.times循环让线程执行产生了时间间隔,避免了瞬时并发的情况。

解决方案

1. 给输出操作加互斥锁

通过Ruby的Mutex实现同步,确保每次puts操作是原子性的,避免并发打断:

PRINT_LOCK = Mutex.new

def safe_puts(str)
  PRINT_LOCK.synchronize do
    puts str
  end
end

def work(n)
  safe_puts "Started unit of work ##{n}."
  i = 0
  100000000.times { i += 1 }
  safe_puts "Finished unit of work ##{n}."
end

threads = []

2.times do |i|
  thread = Thread.new do
    work(i + 1)
  end
  threads << thread
end

threads.each(&:join)

safe_puts "\nEnd."

2. 直接调用Java的同步输出方法

Java的System.out.println方法内部通过同步机制保证了输出的原子性,直接调用该方法可以避免换行丢失问题:

def work(n)
  Java::java.lang.System.out.println("Started unit of work ##{n}.")
  i = 0
  100000000.times { i += 1 }
  Java::java.lang.System.out.println("Finished unit of work ##{n}.")
end

threads = []

2.times do |i|
  thread = Thread.new do
    work(i + 1)
  end
  threads << thread
end

threads.each(&:join)

Java::java.lang.System.out.println("\nEnd.")

3. 升级JRuby版本

该问题可能是特定JRuby版本的已知bug,尝试升级到最新稳定版(如9.4.x系列),新版本可能修复了IO操作的并发同步问题。

内容的提问来源于stack exchange,提问作者Matt Welke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 21:15:39