Java基礎學習之--理解Object類

看Java API的Object類, 一共11個方法。按使用的頻度排名:

  1. toString() 這個方法最常用在打日誌,定位代碼問題。

  2. equals()hashCode(), 這兩個方法的使用經典例子是HashMap的源碼
    public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

equals()hashCode() 要常用一點。

  1. wait()notify() 這個開發很少會直接用到,但是間接用到的場景不少,屬於偏內功的點。wait/notify屬於Object類最難理解的點了,因爲它的基石是多線程。學習思路還是三步走。

step 1: 看文檔說明

wait()
Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.

notify()
Wakes up a single thread that is waiting on this object's monitor.

這個文檔說明,看完基本一頭霧水,兩個方法都提到了如下的核心概念thread, object's monitor。 先把這些概念放一邊,看看是怎麼用的。

step 2: 運行Demo

給個demo輔助理解,一個線程是幹活的,另一個線程是管事的。管事的等活幹完驗收。

public class WaitNotifyDemo {

    static class Worker extends Thread{

        private volatile int status=0; // 1: 完成, -1: 出錯

        @Override
        public void run(){

            try {
                System.out.println(Thread.currentThread().getName() +": 開始幹活");
                Thread.sleep(3000);
                System.out.println(Thread.currentThread().getName() +": 完成任務");

                status = 1;
                // 通知主線程
                synchronized (this){
                    this.notify();
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
                status = -1;
            }
        }

        public int getStatus(){
            return status;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Worker worker= new Worker();
        worker.start();

        synchronized (worker){
            int status;
            while ((status=worker.getStatus())!=1){
                worker.wait();
                if(status==-1)
                    throw new RuntimeException("出錯了");
            }
        }
        System.out.println("任務已經完成");
    }
}

step3: 折騰demo
接下來, 我試了一下, 把notify的代碼去掉,也能正常運行。 這就讓人困惑了,文檔明明說必須調用notify,wait才能結束。接下來再看文檔:

A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup

所以, wait方法必須在while循環中調用。好,解答了一點疑惑。但是每次Worker線程結束時沒有調用notify,主線程就能正常退出, 這個也說不通。 唯一的解釋是: JVM內部在某個地方調用了notify。看openjdk的源碼, 果然如此:從start0開始, 定位到線程在退出時會調用lock.notify_all(thread);。只是這裏的代碼是JVM內部的代碼,比較底層。

其實,這個例子更簡潔的寫法是worker.join()。 如果看Thread.join()的源碼,發現它的實現恰好就是調用了wait。

  1. clone() 這個需要理解深度克隆, 知識點不復雜。

  2. getclass() 這個放在後面,但是用得還挺多的,特別是寫框架。

  3. finalize() 這個已經不他推薦使用了, 儘量不干擾GC的節奏。

總結一下,Object類是Java的基石。這裏比較難一點的就是wait/notify. 學習Java的API, 如果想理解透徹一點,估計繞不開JVM的c++源碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章