Java基礎(chǔ)之Object解析(二)

1. 導(dǎo)讀

接上一篇的分享, 我們一起看一下Object類中剩余的6個方法:
1.1 toString();
1.2 notify();
1.3 notifyAll();
1.4 wait();
1.5 finalize();
1.6 registerNatives();

2. toString方法

toString方法是我們比較常用的方法, 在Object中的默認實現(xiàn)返回一個 類名+'@'+hasCode的16進制拼接的字符串;

    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

注意到toString方法是沒有被final修飾的, 證明他可以被子類重寫;

劃重點:
.1 我們可以根據(jù)自身需求重寫toString方法, 默認實現(xiàn)是返回類名+'@'+hashCode的16進制拼接而成的字符串;
.2 我們調(diào)用System.out.println(obj), 默認調(diào)用的就是obj的toString方法;

3. notify, notifyAll 和 wait方法

把這三個方法放一起是因為這三個方法是配套的, 用來實現(xiàn)JAVA多線程的協(xié)作; 既然是多線程相關(guān)的方法, 為什么會在Object這個類中呢? 這個是因為調(diào)用這三個方法前提都是需要在synchronized修飾的同步代碼塊中, 而synchronized鎖的實現(xiàn)是基于對象(Object)監(jiān)視器的;
那么這三個方法之間是如何協(xié)作的? 每個方法又具體干了什么呢?
3.1 wait: 在同步代碼塊中調(diào)用該方法時, 當前線程立即釋放鎖并等待, 直到有其他線程調(diào)用notify/notifyAll或超時等待時, 才會去再次競爭鎖, 成功后繼續(xù)執(zhí)行下面的邏輯;

    public final native void wait(long timeout) throws InterruptedException;

wait方法被final, native修飾, 證明他是不可被重寫的原生方法; 該方法在等待的時候, 有其他線程打斷了他的等待, 那么他會拋出InterruptedException并退出等待;
Object類中還有wait(), wait(long timeout, int nanos)這兩種wait的實現(xiàn), 但其實都是調(diào)用的wait(long timeout);

3.2 notify: 線程A在同步代碼塊中調(diào)用該方法時, 會隨機地喚醒一個等待在該對象鎖上的線程B, 注意這時候喚醒的線程B還沒有持有鎖, 必須要等到線程A釋放鎖后才能持有該把鎖;
當線程在A對象的同步代碼塊中執(zhí)行B對象的notify時, 會拋出IllegalMonitorStateException;如果沒有這個限制, 我們想想會發(fā)生什么情況;
拿最常用的生產(chǎn)者消費者舉例:
1. 消費者消費(notify生產(chǎn)者);
2. 當貨物不存在時等待生產(chǎn)者生產(chǎn)(wait);
3. 生產(chǎn)者生產(chǎn)貨物(notify消費者);
4. 當貨物沒被消費時等待(wait);
我們期望的是 1-->2-->3-->4-->1-->2...這樣的順序;
但是如果消費者和生產(chǎn)者持有的是兩把不同的對象鎖, 那么當消費者notify時, 因為生產(chǎn)者等待在另一把鎖上, 導(dǎo)致無法喚醒生產(chǎn)者, 那么就會導(dǎo)致:1-->2-->4,生產(chǎn)者和消費者會同時阻塞;
所以為了消除這種競態(tài)條件, 在A對象的同步代碼塊中, 只能調(diào)用A對象的notify方法, 否則就會拋出IllegalMonitorStateException;

3.3 notifyAll: 線程A在同步代碼塊中調(diào)用該方法時, 會喚醒所有等待在該鎖上的線程, 同樣的, 這些喚醒的線程只有在線程A釋放鎖以后, 才能再次競爭該把鎖, 競爭到鎖的線程繼續(xù)執(zhí)行, 其他的線程繼續(xù)等待;
如果調(diào)用的線程不是該把鎖的持有者, 那么也會拋出IllegalMonitorStateException;

    public final native void notify();
    public final native void notifyAll();

nofity 和 notifyAll都是不可重寫的原生方法, 雖然這兩個方法沒有顯式的拋出IllegalMonitorStateException這個異常, 但是當競態(tài)條件產(chǎn)生時, IllegalMonitorStateException這個異常自然就出現(xiàn)了;

劃重點:
.1 執(zhí)行notify | notifyAll時, 喚醒的線程并不會立即持有鎖, 故而會形成假喚醒的情況, 那么在寫wait方法的時, 推薦使用以下方式:

     synchronized(lock) {
        while(!condition) {
            lock.wait();
        }
        //doSomething;
     }

當條件不滿足時, 該線程還需繼續(xù)等待;

.2 執(zhí)行wait | notify | notifyAll的對象, 必須與synchronized鎖住的對象是同一個, 否則會形成競態(tài)條件導(dǎo)致IllegalMonitorStateException異常的產(chǎn)生;
.3 java多線程這塊內(nèi)容較多, 這期只是簡略的介紹下這三個方法, 后面會有一系列的文章專門分享多線程相關(guān)的內(nèi)容;

4. finalize方法

     protected void finalize() throws Throwable { }

java的內(nèi)存管理依賴于JVM實現(xiàn)的GC(Garbage Collection)機制來實現(xiàn)內(nèi)存的回收, GC相關(guān)的內(nèi)容后面再展開; JVM在進行GC時, 如果這個對象需要被回收, 會先判斷該方法是否有被重寫, 若未重寫, 則直接回收該對象內(nèi)存空間;
反之則判斷該對象的finalize是否被執(zhí)行過, 如果沒有執(zhí)行過, 會先放入一個隊列中, 由低優(yōu)先級的線程去執(zhí)行該對象的finalize方法, 執(zhí)行完畢后再判斷該對象是否需要回收;
如果該對象已經(jīng)執(zhí)行過一遍finalize方法了, 直接回收對象的內(nèi)存空間;


image

上圖就是對GC執(zhí)行回收對象finaliz方法時對象狀態(tài)變化的過程;

劃重點:
.1 重寫了finalize方法后, 在對象的整個生命周期中GC只會執(zhí)行一次finalize方法;

5. registerNatives方法

最后來看一下registerNatives方法, 可能看過源碼的同學(xué)都知道這個方法是Object類中的第一個方法, 我把他放到最后將的原因是和他的功能相關(guān);

    private static native void registerNatives();
    static {
        registerNatives();
    }

首先應(yīng)該關(guān)注到的是static代碼塊, 靜態(tài)代碼塊是在類加載時就會執(zhí)行的, 這個代碼塊中只是調(diào)用了registerNatives方法;
再看到registerNatives方法:
5.1 static: 這是個靜態(tài)方法, 因為靜態(tài)只能調(diào)用靜態(tài), 也就是只有靜態(tài)方法才能在靜態(tài)代碼塊中直接調(diào)用;
5.2 native: 原生方法, 他是由C實現(xiàn)的;
5.3 看到方法名, 我們可以猜到他是注冊O(shè)bject類中的原生方法的, 實現(xiàn)java中聲明的native方法與C實現(xiàn)函數(shù)的綁定;

static JNINativeMethod methods[] = {
    {"hashCode",    "()I",                    (void *)&JVM_IHashCode},
    {"wait",        "(J)V",                   (void *)&JVM_MonitorWait},
    {"notify",      "()V",                    (void *)&JVM_MonitorNotify},
    {"notifyAll",   "()V",                    (void *)&JVM_MonitorNotifyAll},
    {"clone",       "()Ljava/lang/Object;",   (void *)&JVM_Clone},
};

JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
{
    (*env)->RegisterNatives(env, cls,
                            methods, sizeof(methods)/sizeof(methods[0]));
}

這是OpenJDK6對Object中native方法的綁定, Java_java_lang_Object_registerNatives這樣函數(shù)可直接調(diào)用java中native函數(shù), 通過上面的代碼可以清晰的看到registerNatives實現(xiàn)了method中native方法的綁定;
同時也可以看到methods中是沒有g(shù)etClass這個方法, 自然可以猜到他也是采用規(guī)定函數(shù)名稱直接調(diào)用的方式實現(xiàn)綁定的(Java_java_lang_Object_getClass);
JNI這里就不做展開, 感興趣的可以閱讀下
Java? Native Interface: Programmer's Guide and Specification;

至此, Object類中的所有方法的解析已經(jīng)告一段落了, 如有錯誤之處, 歡迎指正;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拱烁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蛤高,老刑警劉巖添怔,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件续徽,死亡現(xiàn)場離奇詭異畏妖,居然都是意外死亡傅瞻,警方通過查閱死者的電腦和手機踢代,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嗅骄,“玉大人胳挎,你說我怎么就攤上這事∧缟” “怎么了慕爬?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長屏积。 經(jīng)常有香客問我医窿,道長,這世上最難降的妖魔是什么炊林? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任姥卢,我火速辦了婚禮,結(jié)果婚禮上铛铁,老公的妹妹穿的比我還像新娘隔显。我一直安慰自己,他們只是感情好饵逐,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布括眠。 她就那樣靜靜地躺著,像睡著了一般倍权。 火紅的嫁衣襯著肌膚如雪掷豺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天薄声,我揣著相機與錄音当船,去河邊找鬼。 笑死默辨,一個胖子當著我的面吹牛德频,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播缩幸,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼壹置,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了表谊?” 一聲冷哼從身側(cè)響起钞护,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎爆办,沒想到半個月后难咕,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡距辆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年余佃,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跨算。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡咙冗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出漂彤,到底是詐尸還是另有隱情雾消,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布挫望,位于F島的核電站立润,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏媳板。R本人自食惡果不足惜桑腮,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蛉幸。 院中可真熱鬧破讨,春花似錦丛晦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至隙笆,卻和暖如春锌蓄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背撑柔。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工瘸爽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人铅忿。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓剪决,卻偏偏與公主長得像,于是被迫代替她去往敵國和親檀训。 傳聞我的和親對象是個殘疾皇子昼捍,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355