Java 之 synchronized 詳解

一生蚁、概念

synchronized 是 Java 中的關(guān)鍵字,是利用鎖的機(jī)制來實(shí)現(xiàn)同步的戏自。

鎖機(jī)制有如下兩種特性:

  • 互斥性:即在同一時(shí)間只允許一個(gè)線程持有某個(gè)對(duì)象鎖邦投,通過這種特性來實(shí)現(xiàn)多線程中的協(xié)調(diào)機(jī)制,這樣在同一時(shí)間只有一個(gè)線程對(duì)需同步的代碼塊(復(fù)合操作)進(jìn)行訪問擅笔≈疽拢互斥性我們也往往稱為操作的原子性屯援。

  • 可見性:必須確保在鎖被釋放之前,對(duì)共享變量所做的修改念脯,對(duì)于隨后獲得該鎖的另一個(gè)線程是可見的(即在獲得鎖時(shí)應(yīng)獲得最新共享變量的值)狞洋,否則另一個(gè)線程可能是在本地緩存的某個(gè)副本上繼續(xù)操作從而引起不一致。

二和二、對(duì)象鎖和類鎖

1. 對(duì)象鎖

在 Java 中徘铝,每個(gè)對(duì)象都會(huì)有一個(gè) monitor 對(duì)象耳胎,這個(gè)對(duì)象其實(shí)就是 Java 對(duì)象的鎖惯吕,通常會(huì)被稱為“內(nèi)置鎖”或“對(duì)象鎖”。類的對(duì)象可以有多個(gè)怕午,所以每個(gè)對(duì)象有其獨(dú)立的對(duì)象鎖废登,互不干擾。

2. 類鎖

在 Java 中郁惜,針對(duì)每個(gè)類也有一個(gè)鎖堡距,可以稱為“類鎖”,類鎖實(shí)際上是通過對(duì)象鎖實(shí)現(xiàn)的兆蕉,即類的 Class 對(duì)象鎖羽戒。每個(gè)類只有一個(gè) Class 對(duì)象,所以每個(gè)類只有一個(gè)類鎖虎韵。

三易稠、synchronized 的用法分類

synchronized 的用法可以從兩個(gè)維度上面分類:

1. 根據(jù)修飾對(duì)象分類

synchronized 可以修飾方法和代碼塊

  • 修飾代碼塊

    • synchronized(this|object) {}

    • synchronized(類.class) {}

  • 修飾方法

    • 修飾非靜態(tài)方法

    • 修飾靜態(tài)方法

2. 根據(jù)獲取的鎖分類

  • 獲取對(duì)象鎖

    • synchronized(this|object) {}

    • 修飾非靜態(tài)方法

  • 獲取類鎖

    • synchronized(類.class) {}

    • 修飾靜態(tài)方法

四、synchronized 的用法詳解

這里根據(jù)獲取的鎖分類來分析 synchronized 的用法

1. 獲取對(duì)象鎖

1.1 對(duì)于同一對(duì)象

  • 同步線程類:
class SyncThread implements Runnable {

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        if (threadName.startsWith("A")) {
            async();
        } else if (threadName.startsWith("B")) {
            sync1();
        } else if (threadName.startsWith("C")) {
            sync2();
        }

    }

    /**
     * 異步方法
     */
    private void async() {
        try {
            System.out.println(Thread.currentThread().getName() + "_Async_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + "_Async_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 方法中有 synchronized(this|object) {} 同步代碼塊
     */
    private void sync1() {
        System.out.println(Thread.currentThread().getName() + "_Sync1: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        synchronized (this) {
            try {
                System.out.println(Thread.currentThread().getName() + "_Sync1_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                Thread.sleep(2000);
                System.out.println(Thread.currentThread().getName() + "_Sync1_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * synchronized 修飾非靜態(tài)方法
     */
    private synchronized void sync2() {
        System.out.println(Thread.currentThread().getName() + "_Sync2: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        try {
            System.out.println(Thread.currentThread().getName() + "_Sync2_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + "_Sync2_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  • 測試代碼:
public class SyncTest {

    public static void main(String... args) {
        SyncThread syncThread = new SyncThread();
        Thread A_thread1 = new Thread(syncThread, "A_thread1");
        Thread A_thread2 = new Thread(syncThread, "A_thread2");
        Thread B_thread1 = new Thread(syncThread, "B_thread1");
        Thread B_thread2 = new Thread(syncThread, "B_thread2");
        Thread C_thread1 = new Thread(syncThread, "C_thread1");
        Thread C_thread2 = new Thread(syncThread, "C_thread2");
        A_thread1.start();
        A_thread2.start();
        B_thread1.start();
        B_thread2.start();
        C_thread1.start();
        C_thread2.start();
    }
}
  • 運(yùn)行結(jié)果:
B_thread2_Sync1: 14:44:20
A_thread1_Async_Start: 14:44:20
B_thread1_Sync1: 14:44:20
C_thread1_Sync2: 14:44:20
A_thread2_Async_Start: 14:44:20
C_thread1_Sync2_Start: 14:44:20
A_thread1_Async_End: 14:44:22
A_thread2_Async_End: 14:44:22
C_thread1_Sync2_End: 14:44:22
B_thread1_Sync1_Start: 14:44:22
B_thread1_Sync1_End: 14:44:24
B_thread2_Sync1_Start: 14:44:24
B_thread2_Sync1_End: 14:44:26
C_thread2_Sync2: 14:44:26
C_thread2_Sync2_Start: 14:44:26
C_thread2_Sync2_End: 14:44:28
  • 結(jié)果分析:

    • A 類線程訪問方法中沒有同步代碼塊包蓝,A 類線程是異步的驶社,所以有線程訪問對(duì)象的同步代碼塊時(shí),另外的線程可以訪問該對(duì)象的非同步代碼塊:
    A_thread1_Async_Start: 14:44:20
    A_thread2_Async_Start: 14:44:20
    A_thread1_Async_End: 14:44:22
    A_thread2_Async_End: 14:44:22
    
    • B 類線程訪問的方法中有同步代碼塊测萎,B 類線程是同步的亡电,一個(gè)線程在訪問對(duì)象的同步代碼塊,另一個(gè)訪問對(duì)象的同步代碼塊的線程會(huì)被阻塞:
    B_thread1_Sync1_Start: 14:44:22
    B_thread1_Sync1_End: 14:44:24
    B_thread2_Sync1_Start: 14:44:24
    B_thread2_Sync1_End: 14:44:26
    
    • synchronized(this|object) {} 代碼塊 {} 之外的代碼依然是異步的:
    B_thread2_Sync1: 14:44:20
    B_thread1_Sync1: 14:44:20
    
    • C 類線程訪問的是 synchronized 修飾非靜態(tài)方法硅瞧,C 類線程是同步的份乒,一個(gè)線程在訪問對(duì)象的同步代方法,另一個(gè)訪問對(duì)象同步方法的線程會(huì)被阻塞:
    C_thread1_Sync2_Start: 14:44:20
    C_thread1_Sync2_End: 14:44:22
    C_thread2_Sync2_Start: 14:44:26
    C_thread2_Sync2_End: 14:44:28
    
    • synchronized 修飾非靜態(tài)方法腕唧,作用范圍是整個(gè)方法或辖,所以方法中所有的代碼都是同步的:
    C_thread1_Sync2: 14:44:20
    C_thread2_Sync2: 14:44:26
    
    • 由結(jié)果可知 B 類和 C 類線程順序執(zhí)行,<strong>類中 synchronized(this|object) {} 代碼塊和 synchronized 修飾非靜態(tài)方法獲取的鎖是同一個(gè)鎖四苇,即該類的對(duì)象的對(duì)象鎖孝凌。</strong>所以 B 類線程和 C 類線程也是同步的:
    B_thread1_Sync1_Start: 14:44:22
    B_thread1_Sync1_End: 14:44:24
    C_thread1_Sync2_Start: 14:44:20
    C_thread1_Sync2_End: 14:44:22
    B_thread2_Sync1_Start: 14:44:24
    B_thread2_Sync1_End: 14:44:26
    C_thread2_Sync2_Start: 14:44:26
    C_thread2_Sync2_End: 14:44:28
    

1.2 對(duì)于不同對(duì)象

  • 修改測試代碼為:
public class SyncTest {

    public static void main(String... args) {
        Thread A_thread1 = new Thread(new SyncThread(), "A_thread1");
        Thread A_thread2 = new Thread(new SyncThread(), "A_thread2");
        Thread B_thread1 = new Thread(new SyncThread(), "B_thread1");
        Thread B_thread2 = new Thread(new SyncThread(), "B_thread2");
        Thread C_thread1 = new Thread(new SyncThread(), "C_thread1");
        Thread C_thread2 = new Thread(new SyncThread(), "C_thread2");
        A_thread1.start();
        A_thread2.start();
        B_thread1.start();
        B_thread2.start();
        C_thread1.start();
        C_thread2.start();
    }
}
  • 運(yùn)行結(jié)果:
A_thread2_Async_Start: 15:01:34
C_thread2_Sync2: 15:01:34
B_thread2_Sync1: 15:01:34
C_thread1_Sync2: 15:01:34
B_thread2_Sync1_Start: 15:01:34
B_thread1_Sync1: 15:01:34
C_thread1_Sync2_Start: 15:01:34
A_thread1_Async_Start: 15:01:34
C_thread2_Sync2_Start: 15:01:34
B_thread1_Sync1_Start: 15:01:34
C_thread1_Sync2_End: 15:01:36
A_thread1_Async_End: 15:01:36
C_thread2_Sync2_End: 15:01:36
B_thread2_Sync1_End: 15:01:36
B_thread1_Sync1_End: 15:01:36
A_thread2_Async_End: 15:01:36
  • 結(jié)果分析:

    • 兩個(gè)線程訪問不同對(duì)象的 synchronized(this|object) {} 代碼塊和 synchronized 修飾非靜態(tài)方法是異步的,同一個(gè)類的不同對(duì)象的對(duì)象鎖互不干擾月腋。

2 獲取類鎖

2.1 對(duì)于同一對(duì)象

  • 同步線程類:
class SyncThread implements Runnable {

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        if (threadName.startsWith("A")) {
            async();
        } else if (threadName.startsWith("B")) {
            sync1();
        } else if (threadName.startsWith("C")) {
            sync2();
        }

    }

    /**
     * 異步方法
     */
    private void async() {
        try {
            System.out.println(Thread.currentThread().getName() + "_Async_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + "_Async_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 方法中有 synchronized(類.class) {} 同步代碼塊
     */
    private void sync1() {
        System.out.println(Thread.currentThread().getName() + "_Sync1: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        synchronized (SyncThread.class) {
            try {
                System.out.println(Thread.currentThread().getName() + "_Sync1_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                Thread.sleep(2000);
                System.out.println(Thread.currentThread().getName() + "_Sync1_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * synchronized 修飾靜態(tài)方法
     */
    private synchronized static void sync2() {
        System.out.println(Thread.currentThread().getName() + "_Sync2: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        try {
            System.out.println(Thread.currentThread().getName() + "_Sync2_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + "_Sync2_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  • 測試代碼:
public class SyncTest {

    public static void main(String... args) {
        SyncThread syncThread = new SyncThread();
        Thread A_thread1 = new Thread(syncThread, "A_thread1");
        Thread A_thread2 = new Thread(syncThread, "A_thread2");
        Thread B_thread1 = new Thread(syncThread, "B_thread1");
        Thread B_thread2 = new Thread(syncThread, "B_thread2");
        Thread C_thread1 = new Thread(syncThread, "C_thread1");
        Thread C_thread2 = new Thread(syncThread, "C_thread2");
        A_thread1.start();
        A_thread2.start();
        B_thread1.start();
        B_thread2.start();
        C_thread1.start();
        C_thread2.start();
    }
}
  • 運(yùn)行結(jié)果:
B_thread1_Sync1: 15:08:13
C_thread1_Sync2: 15:08:13
B_thread2_Sync1: 15:08:13
A_thread1_Async_Start: 15:08:13
C_thread1_Sync2_Start: 15:08:13
A_thread2_Async_Start: 15:08:13
C_thread1_Sync2_End: 15:08:15
A_thread2_Async_End: 15:08:15
A_thread1_Async_End: 15:08:15
B_thread2_Sync1_Start: 15:08:15
B_thread2_Sync1_End: 15:08:17
B_thread1_Sync1_Start: 15:08:17
B_thread1_Sync1_End: 15:08:19
C_thread2_Sync2: 15:08:19
C_thread2_Sync2_Start: 15:08:19
C_thread2_Sync2_End: 15:08:21
  • 結(jié)果分析:

    • 由結(jié)果可以看出蟀架,在同一對(duì)象的情況下瓣赂,synchronized(類.class) {} 代碼塊或 synchronized 修飾靜態(tài)方法和 synchronized(this|object) {} 代碼塊和 synchronized 修飾非靜態(tài)方法的行為一致。

2.2 對(duì)于不同對(duì)象

  • 修改測試代碼為:
public class SyncTest {

    public static void main(String... args) {
        Thread A_thread1 = new Thread(new SyncThread(), "A_thread1");
        Thread A_thread2 = new Thread(new SyncThread(), "A_thread2");
        Thread B_thread1 = new Thread(new SyncThread(), "B_thread1");
        Thread B_thread2 = new Thread(new SyncThread(), "B_thread2");
        Thread C_thread1 = new Thread(new SyncThread(), "C_thread1");
        Thread C_thread2 = new Thread(new SyncThread(), "C_thread2");
        A_thread1.start();
        A_thread2.start();
        B_thread1.start();
        B_thread2.start();
        C_thread1.start();
        C_thread2.start();
    }
}
  • 運(yùn)行結(jié)果:
A_thread2_Async_Start: 15:17:28
B_thread2_Sync1: 15:17:28
A_thread1_Async_Start: 15:17:28
B_thread1_Sync1: 15:17:28
C_thread1_Sync2: 15:17:28
C_thread1_Sync2_Start: 15:17:28
C_thread1_Sync2_End: 15:17:30
A_thread2_Async_End: 15:17:30
B_thread1_Sync1_Start: 15:17:30
A_thread1_Async_End: 15:17:30
B_thread1_Sync1_End: 15:17:32
B_thread2_Sync1_Start: 15:17:32
B_thread2_Sync1_End: 15:17:34
C_thread2_Sync2: 15:17:34
C_thread2_Sync2_Start: 15:17:34
C_thread2_Sync2_End: 15:17:36
  • 結(jié)果分析:

    • <strong>兩個(gè)線程訪問不同對(duì)象的 synchronized(類.class) {} 代碼塊或 synchronized 修飾靜態(tài)方法還是同步的片拍,類中 synchronized(類.class) {} 代碼塊和 synchronized 修飾靜態(tài)方法獲取的鎖是類鎖煌集。對(duì)于同一個(gè)類的不同對(duì)象的類鎖是同一個(gè)。</strong>

3 類中同時(shí)有 synchronized(類.class) {} 代碼塊或 synchronized 修飾靜態(tài)方法和 synchronized(this|object) {} 代碼塊和 synchronized 修飾非靜態(tài)方法時(shí)會(huì)怎樣捌省?

  • 修改同步線程類:
class SyncThread implements Runnable {

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        if (threadName.startsWith("A")) {
            async();
        } else if (threadName.startsWith("B")) {
            sync1();
        } else if (threadName.startsWith("C")) {
            sync2();
        }

    }

    /**
     * 異步方法
     */
    private void async() {
        try {
            System.out.println(Thread.currentThread().getName() + "_Async_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + "_Async_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * synchronized 修飾非靜態(tài)方法
     */
    private synchronized void sync1() {
        try {
            System.out.println(Thread.currentThread().getName() + "_Sync1_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + "_Sync1_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * synchronized 修飾靜態(tài)方法
     */
    private synchronized static void sync2() {
        try {
            System.out.println(Thread.currentThread().getName() + "_Sync2_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + "_Sync2_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  • 修改測試代碼:
public class SyncTest {

    public static void main(String... args) {
        Thread B_thread1 = new Thread(syncThread, "B_thread1");
        Thread C_thread1 = new Thread(syncThread, "C_thread1");
        B_thread1.start();
        C_thread1.start();
    }
}
  • 運(yùn)行結(jié)果:
B_thread1_Sync1_Start: 15:35:21
C_thread1_Sync2_Start: 15:35:21
B_thread1_Sync1_End: 15:35:23
C_thread1_Sync2_End: 15:35:23
  • 運(yùn)行結(jié)果分析:

    • 由結(jié)果可以看到 B 類線程和 C 類線程是異步的苫纤,即 synchronized 修飾靜態(tài)方法和 synchronized 修飾非靜態(tài)方法是異步的,對(duì)于 synchronized(類.class) {} 代碼塊和 synchronized(this|object) {} 代碼塊也是一樣的纲缓。<strong>所以對(duì)象鎖和類鎖是獨(dú)立的卷拘,互不干擾。</strong>

4 補(bǔ)充

  1. synchronized關(guān)鍵字不能繼承祝高。

    對(duì)于父類中的 synchronized 修飾方法栗弟,子類在覆蓋該方法時(shí),默認(rèn)情況下不是同步的工闺,必須顯示的使用 synchronized 關(guān)鍵字修飾才行乍赫。

  2. 在定義接口方法時(shí)不能使用synchronized關(guān)鍵字。

  3. 構(gòu)造方法不能使用synchronized關(guān)鍵字陆蟆,但可以使用synchronized代碼塊來進(jìn)行同步雷厂。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市叠殷,隨后出現(xiàn)的幾起案子改鲫,更是在濱河造成了極大的恐慌,老刑警劉巖溪猿,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钩杰,死亡現(xiàn)場離奇詭異,居然都是意外死亡诊县,警方通過查閱死者的電腦和手機(jī)讲弄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來依痊,“玉大人避除,你說我怎么就攤上這事⌒剜遥” “怎么了瓶摆?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長性宏。 經(jīng)常有香客問我群井,道長,這世上最難降的妖魔是什么毫胜? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任书斜,我火速辦了婚禮诬辈,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘荐吉。我一直安慰自己焙糟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布样屠。 她就那樣靜靜地躺著穿撮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪痪欲。 梳的紋絲不亂的頭發(fā)上悦穿,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音勤揩,去河邊找鬼咧党。 笑死秘蛔,一個(gè)胖子當(dāng)著我的面吹牛陨亡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播深员,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼负蠕,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了倦畅?” 一聲冷哼從身側(cè)響起遮糖,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎叠赐,沒想到半個(gè)月后欲账,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡芭概,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年赛不,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罢洲。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡踢故,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惹苗,到底是詐尸還是另有隱情殿较,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布桩蓉,位于F島的核電站淋纲,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏院究。R本人自食惡果不足惜洽瞬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一玷或、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧片任,春花似錦偏友、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至产场,卻和暖如春鹅髓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背京景。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國打工窿冯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人确徙。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓醒串,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鄙皇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子芜赌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Java8張圖 11伴逸、字符串不變性 12缠沈、equals()方法、hashCode()方法的區(qū)別 13错蝴、...
    Miley_MOJIE閱讀 3,693評(píng)論 0 11
  • 本文主要講了java中多線程的使用方法洲愤、線程同步、線程數(shù)據(jù)傳遞顷锰、線程狀態(tài)及相應(yīng)的一些線程函數(shù)用法柬赐、概述等。 首先講...
    李欣陽閱讀 2,442評(píng)論 1 15
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法馍惹,類相關(guān)的語法躺率,內(nèi)部類的語法,繼承相關(guān)的語法万矾,異常的語法悼吱,線程的語...
    子非魚_t_閱讀 31,581評(píng)論 18 399
  • Java多線程學(xué)習(xí) [-] 一擴(kuò)展javalangThread類 二實(shí)現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 2,952評(píng)論 1 18
  • (一)Java部分 1、列舉出JAVA中6個(gè)比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨(dú)云閱讀 7,071評(píng)論 0 62