我在研究一个简单的HelloWorld
java程序中执行了哪些系统调用。对于一个简单的strace
,我注意到没有write
调用,这让我感到可疑:
...
mprotect(0x7f0bcd852000, 4096, PROT_READ) = 0
mprotect(0x7f0bce915000, 790528, PROT_READ) = 0
getpid() = 27931
munmap(0x7f0bcf6ac000, 174284) = 0
getpid() = 27931
mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f0bcf5d6000
clone(child_stack=0x7f0bcf6d5fb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f0bcf6d69d0, tls=0x7f0bcf6d6700, child_tidptr=0x7f0bcf6d69d0) = 27932
futex(0x7f0bcf6d69d0, FUTEX_WAIT, 27932, NULLHello, World
) = 0
munmap(0x7f0bbfa6c000, 140063364) = 0
close(3) = 0
exit_group(0) = ?
+++ exited with 0 +++
因此,正如您在上面看到的,对于正常的strace
调用,只会执行futex
调用,该调用正在等待字符串地址。
因此,我使用-f
参数运行了strace
,以查看所有线程:
[pid 28249] pread64(3, "\312\376\272\276\0\0\0009\0\330\n\0\2\0\3\7\0\4\f\0\5\0\6\1\0\23java/n"..., 6104, 4355323) = 6104
[pid 28249] pread64(3, "\312\376\272\276\0\0\0009\0\306\n\0\2\0\3\7\0\4\f\0\5\0\6\1\0\20java/l"..., 4455, 3263638) = 4455
[pid 28249] write(1, "Hello, World\n", 13Hello, World
) = 13
[pid 28249] pread64(3, "\312\376\272\276\0\0\0009\0(\n\0\2\0\3\7\0\4\f\0\5\0\6\1\0\25java/l"..., 999, 4425942) = 999
[pid 28249] mmap(0x7f9d35ae2000, 16384, PROT_NONE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0) = 0x7f9d35ae2000
[pid 28249] mprotect(0x7f9d2c2e7000, 8192, PROT_READ|PROT_WRITE) = 0
像这样,我可以看到write
调用以及更多的futex
调用。
我的问题是,当System.out.println
被调用时,在线程级究竟发生了什么?Java是否创建了一个专用的打印线程,然后与主线程同步?另外,它们使用什么来进行同步,最终进行futex
调用。
2条答案
按热度按时间wkftcu5l1#
System.out.println
与线程无关(除了PrintStream
方法是同步的,但在无争用的情况下这并不重要)。Java启动器在一个新线程中创建一个JVM,这就是为什么 * 任何 * Java代码(不仅仅是
println
)都在一个非原始线程中执行。在原始线程中运行Java代码通常会导致许多问题,有关详细信息,请参见JDK-6316197。
gab6jxml2#
Java的
System.out
是一个PrintStream
,它的一个方法是:在这里,您可以看到同步(就像在该类的所有其他 print 方法中一样)。
这样做是为了在多个线程写入System.out(或任何其他
PrintStream
)时不会得到乱码文本。至少它更容易控制全字符串参数,而不是写入单个字符。这也是可能的,但可能会导致乱码输出。我不知道其余的,操作系统相关的I/O是如何处理的内部工作,可能还有更多的事情要做。