色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

OpenJDK源碼解析之System.out.println詳解

瀏覽:116日期:2024-07-21 09:34:04
一、前戲

可能不少小伙伴習(xí)慣在代碼中使用sout打印一些信息,就像這樣:

System.out.println('hello world!')

做為一位資深干碼人,本著弘揚(yáng)黨求真務(wù)實(shí)的精神,必須得來(lái)看看這個(gè)sout有何玄機(jī)~~

首先看調(diào)用就知道,out是System類(lèi)的一個(gè)公共靜態(tài)成員變量,進(jìn)入System.java中:

public final static PrintStream out = null;

嗯,不止是public,還是final的。不管,來(lái)找找out是在哪里賦值的。。。。。。日嘛找半天沒(méi)找到?那就試試直接在類(lèi)中搜索: out = ,結(jié)果如下:

OpenJDK源碼解析之System.out.println詳解

完?duì)僮?,整個(gè)System類(lèi)一共將近1300行的代碼,只找到一個(gè)和out賦值相關(guān)的,還是啥子局部變量fdOut,看起來(lái)和out屬性沒(méi)有什么關(guān)聯(lián)啊~ 往上滑滑看看這個(gè)是什么方法:

private static void initializeSystemClass() {......FileInputStream fdIn = new FileInputStream(FileDescriptor.in);FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);setIn0(new BufferedInputStream(fdIn));setOut0(newPrintStream(fdOut, props.getProperty('sun.stdout.encoding')));setErr0(newPrintStream(fdErr, props.getProperty('sun.stderr.encoding')));......}

原來(lái)如此,看到initializeSystemClass方法,似乎一切都明了了~~

二、JVM源碼分析

initializeSystemClass不是給我們調(diào)用的,這個(gè)方法會(huì)在vm線程初始化后被虛擬機(jī)調(diào)用。其定義在thread.cpp中:

static void call_initializeSystemClass(TRAPS) { Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(), true, CHECK); instanceKlassHandle klass (THREAD, k); JavaValue result(T_VOID); JavaCalls::call_static(&result, klass, vmSymbols::initializeSystemClass_name(), vmSymbols::void_method_signature(), CHECK);}

首先獲取Klass(類(lèi)元信息在虛擬機(jī)中的結(jié)構(gòu)表示,就是一個(gè)c++中的類(lèi)),在vmSymbols.hpp中找找java_lang_System對(duì)應(yīng)的值:

template(java_lang_System, 'java/lang/System')

可以看到代表的就是java.lang.System類(lèi),同時(shí),initializeSystemClass_name也定義在vmSymbols.hpp中:

template(initializeSystemClass_name,'initializeSystemClass')

這里使用JavaCalls::call_static就是調(diào)用java.lang.System的靜態(tài)方法initializeSystemClass。還要再??亂瘓洌?all_initializeSystemClass是在何處調(diào)用的?我們回到thread.cpp中,進(jìn)入Threads::create_vm方法,在其中找到了call_initializeSystemClass方法的調(diào)用:

jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {...... call_initializeSystemClass(CHECK_0);......}

然后看看Threads::create_vm是在何處調(diào)用的,我們進(jìn)入jni.cpp,找到JNI_CreateJavaVM方法:

_JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, void *args) {......result = Threads::create_vm((JavaVMInitArgs*) args, &can_try_again);if (result == JNI_OK) {......} else {......}......}

現(xiàn)在已經(jīng)知道了,JVM啟動(dòng)后會(huì)在初始化JVM的時(shí)候調(diào)用CreateJavaVM,進(jìn)而調(diào)用initializeSystemClass方法。但是out屬性是如何設(shè)置的呢?我們回到j(luò)ava.lang.System#initializeSystemClass方法:

private static void initializeSystemClass() {......FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);setOut0(newPrintStream(fdOut, props.getProperty('sun.stdout.encoding')));......}private static PrintStream newPrintStream(FileOutputStream fos, String enc) { if (enc != null) { try {return new PrintStream(new BufferedOutputStream(fos, 128), true, enc); } catch (UnsupportedEncodingException uee) {}}return new PrintStream(new BufferedOutputStream(fos, 128), true); }

這個(gè)方法中唯一和out相關(guān)的就是這個(gè)setOut0方法調(diào)用了,我們來(lái)看看這個(gè)方法:

private static native void setOut0(PrintStream out);

嗯,這個(gè)是一個(gè)native方法,沒(méi)辦法,又只有回到JVM源碼了。怎么找呢?首選組裝一下本地方法名,根據(jù)規(guī)則setOut0對(duì)應(yīng)的本地方法應(yīng)該叫:Java_java_lang_System_setOut0,我們到源碼中找找,然后在System.c中找到了該方法

JNIEXPORT void JNICALLJava_java_lang_System_setOut0(JNIEnv *env, jclass cla, jobject stream){ jfieldID fid =(*env)->GetStaticFieldID(env,cla,'out','Ljava/io/PrintStream;'); if (fid == 0)return; (*env)->SetStaticObjectField(env,cla,fid,stream);}

首先獲取了java.io.PrintStread類(lèi)型的out靜態(tài)成員,嗯,這個(gè)就是我們java.lang.System類(lèi)的靜態(tài)成員out:

public final static PrintStream out;

然后將stream參數(shù)賦值給它,這個(gè)stream就是initializeSystemClass方法中通過(guò)newPrintStream方法創(chuàng)建的PrintStream 對(duì)象。到現(xiàn)在我們已經(jīng)明白了,out原來(lái)是這樣賦值的,真麻煩~

趁熱打鐵,弄明白了out,接下來(lái)看看println。既然out是PrintStream對(duì)象,那么到PrintStream中看看println方法:

public void println(String x) {synchronized (this) { print(x); newLine();} }

Java代碼看起來(lái)是要親切多了,但是這個(gè)synchronized是個(gè)什么鬼???

三、坑?

前面我們發(fā)現(xiàn)println方法竟然有個(gè)synchronized關(guān)鍵字,經(jīng)常在項(xiàng)目中使用sout的小伙伴會(huì)不會(huì)感覺(jué)腦袋嗡嗡的?為什么要嗡嗡?不要忘記我們前面通過(guò)JVM源碼跟蹤的System.out的賦值過(guò)程,這個(gè)out可是單例!你個(gè)加了synchronized(this)的虛方法,還是單例的,如果在系統(tǒng)中進(jìn)行并發(fā)使用,后果不用我多說(shuō)吧?

那可能有人就要說(shuō)了,那我不用println(“hello world!”)了嘛,我換成print總行了吧?

System.out.print('hello world!');System.out.print('n');

因?yàn)閜rint方法好像沒(méi)有加鎖?。?/p>

public void print(String s) {if (s == null) { s = 'null';}write(s); }

那我們看看write方法,不好意思:

private void write(String s) {try { synchronized (this) {ensureOpen();textOut.write(s);textOut.flushBuffer();charOut.flushBuffer();if (autoFlush && (s.indexOf(’n’) >= 0)) out.flush(); }}...... }四、總結(jié)

不知道有沒(méi)有小伙伴經(jīng)常在項(xiàng)目中使用System.out.println來(lái)輸出'日志'?千萬(wàn)不要亂用喲,不然說(shuō)不定哪天就被out了~~~

到此這篇關(guān)于OpenJDK源碼解析之System.out.println詳解的文章就介紹到這了,更多相關(guān)OpenJDK源碼解析內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: OpenJDK
主站蜘蛛池模板: 成人区精品一区二区不卡亚洲 | 国产剧情一区二区 | 精品久久在线 | 亚洲国产精品自产拍在线播放 | 男女同床爽爽视频免费 | 成人禁在线观看网站 | 男人和女人的做刺激性视频 | 在线 | 一区二区三区四区 | 精品国产香港三级 | 亚洲视频在线免费 | 日日摸天天摸狠狠摸视频 | 久久免费在线视频 | 欧美一区二区三区播放 | 岛国精品成人 | 国产区网址 | 欧美黄色网络 | 19+韩国主播青草vip视频 | 久久爱噜噜噜噜久久久网 | 99久久精品免费看国产免费 | 亚洲在线中文字幕 | 欧美区一区 | 亚洲精品15p | 成人看的午夜免费毛片 | 日韩特黄特色大片免费视频 | 国产成人精品一区二区免费视频 | 9191在线亚洲精品 | 欧美自拍在线 | 成年午夜性视频免费播放 | 久久精品国产精品亚洲综合 | 长腿嫩模打开双腿呻吟 | 寡妇一级a毛片免费播放 | 最新国产三级 | 久草综合视频在线 | 精品国产一区二区三区在线观看 | 玖玖香蕉视频 | 成人免费午夜视频 | 亚洲精品一区国产二区 | 精品国产九九 | 6080伦理久久精品亚洲 | 久久久久亚洲香蕉网 | 99国产成人高清在线视频 |