国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java 多線程中篇

snowell / 1316人閱讀

摘要:異步線程運(yùn)行線程運(yùn)行我們創(chuàng)建兩個(gè)線程來調(diào)用同一業(yè)務(wù)對(duì)象的相同功能時(shí)可以看到下面輸出線程運(yùn)行線程運(yùn)行兩個(gè)線程在一起執(zhí)行方法并且交叉打印也就是說當(dāng)我們啟動(dòng)一個(gè)線程執(zhí)行某個(gè)方法的時(shí)候就是異步執(zhí)行至于為啥要這樣演示是因?yàn)橄旅娴耐酵綄⒎椒ㄉ霞尤腙P(guān)

異步
public class PrintObject {
    public void printString(){
        System.out.println("begin");
        if(Thread.currentThread().getName().equals("a")){
            PrintStream printStream = System.out;
            printStream.println("線程 a 運(yùn)行");
        }
        if(Thread.currentThread().getName().equals("b")){
            System.out.println("線程 b 運(yùn)行");
        }
        System.out.println("end");
    }
}
public static void main(String[] a) {
    PrintObject pb = new PrintObject();

    Thread thread1 = new Thread(pb::printString);
    thread1.setName("a");
    thread1.start();

    Thread thread2 = new Thread(pb::printString);
    thread2.setName("b");
    thread2.start();
}

我們創(chuàng)建兩個(gè)線程來調(diào)用同一業(yè)務(wù)對(duì)象的相同功能時(shí), 可以看到下面輸出.

begin
begin
線程 a 運(yùn)行
end
線程 b 運(yùn)行
end

兩個(gè)線程在一起執(zhí)行 printString 方法, 并且交叉打印. 也就是說當(dāng)我們啟動(dòng)一個(gè)線程執(zhí)行某個(gè)方法的時(shí)候就是異步執(zhí)行, 至于為啥要這樣演示, 是因?yàn)橄旅娴耐?

同步

synchronized public void printString() 方法上加入 synchronized 關(guān)鍵字, 來使方法同步.

執(zhí)行結(jié)果:

begin
線程 a 運(yùn)行
end
begin
線程 b 運(yùn)行
end

那么為什么加入 synchronized 關(guān)鍵字后就會(huì)同步呢? 這是因?yàn)殛P(guān)鍵字 synchronized 會(huì)取得一把對(duì)象鎖, 而不是把一段代碼或方法當(dāng)做鎖; 哪個(gè)線程先執(zhí)行帶 synchronized 關(guān)鍵字的方法, 哪個(gè)線程就持有該方法所屬的對(duì)象的鎖 Look, 那么其他線程只能呈等待狀態(tài).

這里有個(gè)前提是多個(gè)線程訪問同一個(gè)對(duì)象, 下面演示的是多個(gè)線程訪問不同的對(duì)象.

public class PrintObject {
    synchronized public void printString(){
        System.out.println("begin");
        if(Thread.currentThread().getName().equals("a")){
            PrintStream printStream = System.out;
            printStream.println("線程 a 運(yùn)行");
            try {
                Thread.sleep(100000);
            } catch (InterruptedException e) {
                
            }
        }
        if(Thread.currentThread().getName().equals("b")){
            System.out.println("線程 b 運(yùn)行");
        }
        System.out.println("end");
    }
}
    public static void main(String[] a) {
        PrintObject pb = new PrintObject();
        PrintObject pb1 = new PrintObject();

        Thread thread1 = new Thread(pb::printString);
        thread1.setName("a");
        thread1.start();

        Thread thread2 = new Thread(pb1::printString);
        thread2.setName("b");
        thread2.start();
    }

執(zhí)行結(jié)果

begin
線程 a 運(yùn)行
begin
線程 b 運(yùn)行
end

讓 a 線程睡眠 100000 毫秒, 可以看到 a 線程并沒有執(zhí)行完, b 線程就運(yùn)行了. 這也能夠證明 synchronized 關(guān)鍵字取得是對(duì)象鎖.

另外還需要注意一點(diǎn), 我們使用兩個(gè)線程執(zhí)行同一對(duì)象的不同同步方法時(shí), 如果線程 a 在睡眠, 那么線程 b 也會(huì)一直等待, 線程 a 執(zhí)行完畢后再去執(zhí)行.

注: 同步方法一定是線程安全的.
synchronized 鎖重入

如果一個(gè)獲取鎖的線程調(diào)用其它的synchronized修飾的方法, 會(huì)發(fā)生什么?

在一個(gè)線程使用synchronized方法時(shí)調(diào)用該對(duì)象另一個(gè)synchronized方法, 即一個(gè)線程得到一個(gè)對(duì)象鎖后再次請(qǐng)求該對(duì)象鎖, 是永遠(yuǎn)可以拿到鎖的.

在Java內(nèi)部, 同一個(gè)線程調(diào)用自己類中其他synchronized方法/塊時(shí)不會(huì)阻礙該線程的執(zhí)行, 同一個(gè)線程對(duì)同一個(gè)對(duì)象鎖是可重入的, 同一個(gè)線程可以獲取同一把鎖多次, 也就是可以多次重入. 原因是Java中線程獲得對(duì)象鎖的操作是以線程為單位的, 而不是以調(diào)用為單位的.

這種情況也可以發(fā)生在繼承中, 也就是說子類的同步方法調(diào)用父類的同步方式時(shí), 時(shí)可以鎖重入的. 
但是, 如果子類重寫了父類的方法, 并沒有使用 synchronized 關(guān)鍵字, 則同步就失效了. 因?yàn)樽宇愔貙懜割惖姆椒? 當(dāng)我們調(diào)用方法執(zhí)行代碼時(shí), 執(zhí)行的是子類的方法, 所以變成了異步執(zhí)行.
synchronized 同步代碼塊
public class PrintObject {
     public synchronized void printString(){
        try {
            System.out.println(Thread.currentThread().getName() + " 執(zhí)行");
            System.out.println(Thread.currentThread().getName() + " 插入數(shù)據(jù)到數(shù)據(jù)庫");
            // 讓線程休眠, 模擬出網(wǎng)絡(luò)延時(shí)
            Thread.sleep(5000);

            System.out.println(Thread.currentThread().getName() + " 共享數(shù)據(jù)減1");
            Thread.sleep(5000);

            System.out.println(Thread.currentThread().getName() + " 插入數(shù)據(jù)到數(shù)據(jù)庫");
            Thread.sleep(5000);

            if (Thread.currentThread().getName().equals("b")) {
                SimpleDateFormat df = new SimpleDateFormat("mm:ss");
                System.out.println(df.format(new Date()));
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
PrintObject pb = new PrintObject();

Thread thread1 = new Thread(pb::printString);
thread1.setName("a");

Thread thread2 = new Thread(pb::printString);
thread2.setName("b");

SimpleDateFormat df = new SimpleDateFormat("mm:ss");
System.out.println(df.format(new Date()));

thread1.start();
thread2.start();

執(zhí)行結(jié)果

47:34
a 執(zhí)行
a 插入數(shù)據(jù)到數(shù)據(jù)庫
a 共享數(shù)據(jù)減1
a 插入數(shù)據(jù)到數(shù)據(jù)庫
b 執(zhí)行
b 插入數(shù)據(jù)到數(shù)據(jù)庫
b 共享數(shù)據(jù)減1
b 插入數(shù)據(jù)到數(shù)據(jù)庫
48:04

我們上面這段程序兩個(gè)線程全部執(zhí)行完所用的時(shí)間為 30 秒, 這里可以看出同步方法存在一個(gè)很大的弊端.

就是說我們的某個(gè)線程開始執(zhí)行方法時(shí), 無論我們操作的是不是共享數(shù)據(jù), 別的線程都會(huì)等待此線程釋放鎖. 然后繼續(xù)執(zhí)行.

可是我們在插入數(shù)據(jù)到數(shù)據(jù)庫的時(shí)候, 并不是在操作共享數(shù)據(jù), 那么我們有沒有什么辦法, 只同步操作共享數(shù)據(jù)的那部分代碼呢?

我們就可以使用 synchronized 同步代碼塊, 將程序修改成下面樣子.

public class PrintObject {
     public void printString(){
        try {
            System.out.println(Thread.currentThread().getName() + " 執(zhí)行");
            System.out.println(Thread.currentThread().getName() + " 插入數(shù)據(jù)到數(shù)據(jù)庫");
            // 讓線程休眠, 模擬出網(wǎng)絡(luò)延時(shí)
            Thread.sleep(5000);

            synchronized(this) {
                System.out.println(Thread.currentThread().getName() + " 共享數(shù)據(jù)減1");
                Thread.sleep(5000);
            }


            System.out.println(Thread.currentThread().getName() + " 插入數(shù)據(jù)到數(shù)據(jù)庫");
            Thread.sleep(5000);

            if (Thread.currentThread().getName().equals("b")) {
                SimpleDateFormat df = new SimpleDateFormat("mm:ss");
                System.out.println(df.format(new Date()));
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

執(zhí)行結(jié)果

54:12
b 執(zhí)行
a 執(zhí)行
b 插入數(shù)據(jù)到數(shù)據(jù)庫
a 插入數(shù)據(jù)到數(shù)據(jù)庫
a 共享數(shù)據(jù)減1
a 插入數(shù)據(jù)到數(shù)據(jù)庫
b 共享數(shù)據(jù)減1
b 插入數(shù)據(jù)到數(shù)據(jù)庫
54:32

減少了10秒的執(zhí)行時(shí)間, 提高了執(zhí)行效率.

同步方法和同步代碼塊的鎖都是同一把鎖. 同步方法獲取的是該方法的對(duì)象鎖, 而同步代碼塊獲取中的參數(shù)是 this, 表示當(dāng)前對(duì)象. 所以獲取的是同一把鎖.
靜態(tài)同步 synchronized 方法與 synchronized(class) 代碼塊

synchronized 關(guān)鍵字可以應(yīng)用在 static 靜態(tài)方法上, 表示當(dāng)前的 *.java 文件對(duì)應(yīng)的 Class 類進(jìn)行持鎖.

雖然運(yùn)行結(jié)果與 synchronized 關(guān)鍵字加到非 static 靜態(tài)方法上的結(jié)果類似, 但是是對(duì) Class 類進(jìn)行加鎖, 而 Class 鎖可以對(duì)類的所有對(duì)象起作用.

synchronized (DemoApplication.class) {
            
}

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/73654.html

相關(guān)文章

  • 【page-monitor 前端自動(dòng)化 中篇】 源碼分析

    摘要:上篇中初探了的一些功能和在前端自動(dòng)化測試方面的可行性,本篇主要分析下的實(shí)現(xiàn)方式和源碼。文件分析完整文件目錄運(yùn)行生成目錄分析出了及其組件代碼,可用和值的分析的文件和下面的五個(gè)文件。相關(guān)文章前端自動(dòng)化上篇初步調(diào)研前端自動(dòng)化下篇實(shí)踐應(yīng)用 上篇中初探了page-monitor的一些功能和在前端自動(dòng)化測試方面的可行性,本篇主要分析下page-monitor的實(shí)現(xiàn)方式和源碼。 mode-modul...

    Object 評(píng)論0 收藏0
  • Android網(wǎng)絡(luò)編程8之源碼解析OkHttp中篇[復(fù)用連接池]

    摘要:構(gòu)造函數(shù)默認(rèn)空閑的最大連接數(shù)為個(gè),的時(shí)間為秒通過構(gòu)造函數(shù)可以看出默認(rèn)的空閑的最大連接數(shù)為個(gè),的時(shí)間為秒。實(shí)例化實(shí)例化是在實(shí)例化時(shí)進(jìn)行的在的構(gòu)造函數(shù)中調(diào)用了省略省略緩存操作提供對(duì)進(jìn)行操作的方法分別為和幾個(gè)操作。 1.引子 在了解OkHttp的復(fù)用連接池之前,我們首先要了解幾個(gè)概念。 TCP三次握手 通常我們進(jìn)行HTTP連接網(wǎng)絡(luò)的時(shí)候我們會(huì)進(jìn)行TCP的三次握手,然后傳輸數(shù)據(jù),然后再釋放連接...

    fasss 評(píng)論0 收藏0
  • Java 虛擬機(jī)總結(jié)給面試的你(下)

    摘要:本篇博客主要針對(duì)虛擬機(jī)的晚期編譯優(yōu)化,內(nèi)存模型與線程,線程安全與鎖優(yōu)化進(jìn)行總結(jié),其余部分總結(jié)請(qǐng)點(diǎn)擊虛擬總結(jié)上篇,虛擬機(jī)總結(jié)中篇。 本篇博客主要針對(duì)Java虛擬機(jī)的晚期編譯優(yōu)化,Java內(nèi)存模型與線程,線程安全與鎖優(yōu)化進(jìn)行總結(jié),其余部分總結(jié)請(qǐng)點(diǎn)擊Java虛擬總結(jié)上篇 ,Java虛擬機(jī)總結(jié)中篇。 一.晚期運(yùn)行期優(yōu)化 即時(shí)編譯器JIT 即時(shí)編譯器JIT的作用就是熱點(diǎn)代碼轉(zhuǎn)換為平臺(tái)相關(guān)的機(jī)器碼...

    amc 評(píng)論0 收藏0
  • 前端20個(gè)靈魂拷問 徹底搞明白你就是中級(jí)前端工程師 【下篇】

    摘要:安裝后已經(jīng)完成了安裝,并且等待其他的線程被關(guān)閉。激活后在這個(gè)狀態(tài)會(huì)處理事件回調(diào)提供了更新緩存策略的機(jī)會(huì)。并可以處理功能性的事件請(qǐng)求后臺(tái)同步推送。廢棄狀態(tài)這個(gè)狀態(tài)表示一個(gè)的生命周期結(jié)束。 showImg(https://segmentfault.com/img/bVbwWJu?w=2056&h=1536); 不知不覺,已經(jīng)來到了最后的下篇 其實(shí)我寫的東西你如果認(rèn)真去看,跟著去寫,應(yīng)該能有...

    fireflow 評(píng)論0 收藏0
  • 前端20個(gè)靈魂拷問 徹底搞明白你就是中級(jí)前端工程師 【中篇

    摘要:前端個(gè)靈魂拷問,徹底搞明白你就是中級(jí)前端工程師上篇感覺大家比較喜歡看這種類型的文章,以后會(huì)多一些。所有依賴這個(gè)模塊的語句,都定義在一個(gè)回調(diào)函數(shù)中,等到加載完成之后,這個(gè)回調(diào)函數(shù)才會(huì)運(yùn)行。此規(guī)范其實(shí)是在推廣過程中產(chǎn)生的。 showImg(https://segmentfault.com/img/bVbwAMU?w=700&h=394); 前端20個(gè)靈魂拷問,徹底搞明白你就是中級(jí)前端工程師...

    MartinDai 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<