成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

java 多線程基礎(chǔ), 我覺得還是有必要看看的

kohoh_ / 2031人閱讀

摘要:主線程名我們啟動(dòng)的一個(gè)程序可以理解為一個(gè)進(jìn)程一個(gè)進(jìn)程中包含一個(gè)主線程線程可以理解為一個(gè)子任務(wù)中可以通過下面代碼來獲取默認(rèn)的主線程名運(yùn)行結(jié)果為這是線程的名字并不是方法通過此線程來執(zhí)行方法而已兩種方式創(chuàng)建線程繼承類實(shí)現(xiàn)接口實(shí)現(xiàn)接口并且多線程運(yùn)行

Java 主線程名

我們啟動(dòng)的一個(gè)程序可以理解為一個(gè)進(jìn)程, 一個(gè)進(jìn)程中包含一個(gè)主線程, 線程可以理解為一個(gè)子任務(wù). Java 中可以通過下面代碼來獲取默認(rèn)的主線程名.

System.out.println(Thread.currentThread().getName());

運(yùn)行結(jié)果為 main, 這是線程的名字并不是 main 方法, 通過此線程來執(zhí)行 main 方法而已.

兩種方式創(chuàng)建線程

1.繼承 Thread 類

public class Thread1 extends Thread {
    @Override
    public void run() {
        System.out.println("qwe");
    }
}

2.實(shí)現(xiàn) Runnable 接口

public class Thread2 implements Runnable {
    @Override
    public void run() {
        System.out.println("asd");
    }
}
Thread 實(shí)現(xiàn) Runnable 接口. 并且多線程運(yùn)行時(shí), 代碼的執(zhí)行順序與調(diào)用順序是無關(guān)的. 另外如果多次調(diào)用 start方法則會(huì)拋出 java.lang.IllegalThreadStateException
currentThread 方法

返回當(dāng)前代碼正在被哪個(gè)線程調(diào)用.

public class Thread1 extends Thread {

    public Thread1() {
        System.out.println("構(gòu)造方法的打?。? + Thread.currentThread().getName());
    }

    @Override
    public void run() {
        System.out.println("run 方法的打?。? + Thread.currentThread().getName());
    }
}
Thread1 thread1 = new Thread1();
thread1.start();
isAlive 方法

判斷當(dāng)前線程是否處于活動(dòng)狀態(tài).

public class Thread1 extends Thread {
    @Override
    public void run() {
        System.out.println("run 方法的打印 Thread.currentThread().isAlive() == " + Thread.currentThread().isAlive());
        System.out.println("run 方法的打印 this.isAlive() == " + this.isAlive());
        System.out.println("run 方法的打印 Thread.currentThread().isAlive() == this.isAlive() == " + (Thread.currentThread() == this ? "true" : "false"));
    }
}
Thread1 thread1 = new Thread1();

System.out.println("begin == " + thread1.isAlive());
thread1.start();
Thread.sleep(1000);
System.out.println("end == " + thread1.isAlive());

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

begin == false
run 方法的打印 Thread.currentThread().isAlive() == true
run 方法的打印 this.isAlive() == true
run 方法的打印 Thread.currentThread() == this == true
end == false

thread1 在 1秒之后執(zhí)行完成. 所以輸出結(jié)果為 false. 并且 Thread.currentThread()this 是同一個(gè)對(duì)象, 可以理解成執(zhí)行當(dāng)前 run 方法的線程對(duì)象就是我們自己(this).

如果將線程對(duì)象以構(gòu)造參數(shù)的方式傳遞給 Thread 對(duì)象進(jìn)行 start() 啟動(dòng)時(shí), 運(yùn)行結(jié)果和前面實(shí)例是有差異的. 造成這樣的差異的原因還是來自于 Thread.currentThread()this 的差異.

System.out.println("begin == " + thread1.isAlive());
//thread1.start();
// 如果將線程對(duì)象以構(gòu)造參數(shù)的方式傳遞給 Thread 對(duì)象進(jìn)行 start() 啟動(dòng)
Thread thread = new Thread(thread1);
thread.start();

Thread.sleep(1000);
System.out.println("end == " + thread1.isAlive());

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

begin == false
run 方法的打印 Thread.currentThread().isAlive() == true
run 方法的打印 this.isAlive() == false
run 方法的打印 Thread.currentThread() == this == false
end == false

Thread.currentThread().isAlive()true 的原因是因?yàn)? Thread.currentThread() 返回的是 thread 對(duì)象, 而我們也是通過此對(duì)象來啟動(dòng)線程的, 所以是在活動(dòng)狀態(tài).

this.isAlive()false 就比較好理解了, 因?yàn)槲覀兪峭ㄟ^ thread 對(duì)象啟動(dòng)的線程來執(zhí)行 run 方法的. 所以它是 false. 同時(shí)也說明這兩個(gè)不是同一個(gè)對(duì)象.

sleep 方法

在指定的毫秒數(shù)內(nèi)讓當(dāng)前 "正在執(zhí)行的線程" 休眠. "正在執(zhí)行的線程" 只得是 Thread.currentThread() 返回的線程.

Thread.sleep(1000);
停止線程

停止一個(gè)線程意味著在線程處理完任務(wù)之前停掉正在做的操作, 也就是放棄當(dāng)前的操作.

在 Java 中有以下 3 種方法可以終止正在運(yùn)行的線程:

使用退出標(biāo)志, 使線程正常退出, 也就是當(dāng) run 方法完成后線程終止.

使用 stop 方法強(qiáng)行終止線程, 但是不推薦使用這個(gè)方法.

使用 interrupt 方法中斷線程.

停不了的線程

調(diào)用 interrupt 方法僅僅是當(dāng)前線程打了一個(gè)停止標(biāo)記, 并不是真正的停止線程.

public class Thread1 extends Thread {
    @Override
    public void run() {

        for(int i = 0; i < 500000; i++) {
            System.out.println(i);
        }
    }
}
Thread1 thread1 = new Thread1();
thread1.start();
Thread.sleep(2000);
thread1.interrupt();

我們兩秒后調(diào)用 interrupt 方法, 根據(jù)打印結(jié)果我們可以看到線程并沒有停止, 而是在執(zhí)行完 500000 此循環(huán)后 run 方法結(jié)束線程停止.

判斷線程是否是停止?fàn)顟B(tài)

我們將線程標(biāo)記為停止后, 需要在線程內(nèi)部判斷一下這個(gè)線程是否是停止標(biāo)記, 如果是則停止線程.

兩種判斷方法:

Thread.interrupted(); 也可以使用 this.interrupted();

this.isInterrupted();

下面是兩個(gè)方法的源碼:

    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }
    
    public boolean isInterrupted() {
        return isInterrupted(false);
    }

interrupted() 方法數(shù)據(jù)靜態(tài)方法, 也就是判斷當(dāng)前線程是否已經(jīng)中斷. isInterrupted() 判斷線程是否已經(jīng)被中斷.

來自官網(wǎng)的 interrupted() 方法重點(diǎn).
線程的 中斷狀態(tài) 由該方法清除. 換句話說, 如果連續(xù)兩次調(diào)用該方法, 則第二次調(diào)用將返回 false (在第一次調(diào)用已清除了其中斷狀態(tài)之后, 且第二次調(diào)用檢驗(yàn)完中斷狀態(tài)前, 當(dāng)前線程再次中斷的情況除外).
異常停止線程
public class Thread1 extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 500000; i++) {
                if (this.isInterrupted()) {
                    System.out.println("線程停止");
                    throw new InterruptedException();
                }

                System.out.println("i = " + i);
            }
        } catch (InterruptedException e) {
            System.out.println("線程通過 catch 停止");
            e.printStackTrace();
        }
    }
}
Thread1 thread1 = new Thread1();
thread1.start();
Thread.sleep(1000);
thread1.interrupt();

輸出結(jié)果, 這是最后幾行:

i = 195173
i = 195174
i = 195175
線程停止
線程通過 catch 停止
java.lang.InterruptedException
    at Thread1.run(Thread1.java:9)
當(dāng)然我們也可以將 throw new InterruptedException(); 換成 return. 都是一樣可以結(jié)束線程的.
在沉睡中停止

如果線程調(diào)用 Thread.sleep() 方法使線程進(jìn)行休眠, 這時(shí)我們調(diào)用 thread1.interrupt()后會(huì)拋出. InterruptedException 異常.

java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at Thread1.run(Thread1.java:8)
暴力停止線程

暴力停止線程可以使用 stop 方法, 但此方法已經(jīng)過時(shí)并不推薦使用, 原因如下.

即刻拋出 ThreadDeath 異常, 在線程的run()方法內(nèi), 任何一點(diǎn)都有可能拋出ThreadDeath Error, 包括在 catch 或 finally 語句中. 也就是說代碼不確定執(zhí)行到哪一步就會(huì)拋出異常.

釋放該線程所持有的所有的鎖. 這可能會(huì)導(dǎo)致數(shù)據(jù)不一致性.

public class Thread1 extends Thread {

    private String userName = "a";
    private String pwd = "aa";

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public void run() {
        this.userName = "b";
        try {
            Thread.sleep(100000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.pwd = "bb";

    }
}
Thread1 thread1 = new Thread1();
thread1.start();
Thread.sleep(1000);
thread1.stop();

System.out.println(thread1.getUserName() + "     " + thread1.getPwd());

輸出結(jié)果為:

b     aa

我們?cè)诖a中然線程休眠 Thread.sleep(100000); 是為了模擬一些其它業(yè)務(wù)邏輯處理所用的時(shí)間, 在線程處理其它業(yè)務(wù)的時(shí)候, 我們調(diào)用 stop 方法來停止線程.

線程是被停止了也執(zhí)行了 System.out.println(thread1.getUserName() + " " + thread1.getPwd()); 來幫我們輸出結(jié)果, 但是 this.pwd = "bb"; 并沒有被執(zhí)行.

所以, 當(dāng)調(diào)用了 stop 方法后, 線程無論執(zhí)行到哪段代碼, 線程就會(huì)立即退出, 并且會(huì)拋出 ThreadDeath 異常, 而且會(huì)釋放所有鎖, 從而導(dǎo)致數(shù)據(jù)不一致的情況.

interrupt 相比 stop 方法更可控, 而且可以保持?jǐn)?shù)據(jù)一致, 當(dāng)你的代碼邏輯執(zhí)行完一次, 下一次執(zhí)行的時(shí)候, 才會(huì)去判斷并退出線程.

如果大家不怎么理解推薦查看 為什么不能使用Thread.stop()方法? 這篇文章. 下面是另一個(gè)比較好的例子.

如果線程當(dāng)前正持有鎖(此線程可以執(zhí)行代碼), stop之后則會(huì)釋放該鎖. 由于此錯(cuò)誤可能出現(xiàn)在很多地方, 那么這就讓編程人員防不勝防, 極易造成對(duì)象狀態(tài)的不一致. 例如, 對(duì)象 obj 中存放著一個(gè)范圍值: 最小值low, 最大值high, 且low不得大于high, 這種關(guān)系由鎖lock保護(hù), 以避免并發(fā)時(shí)產(chǎn)生競(jìng)態(tài)條件而導(dǎo)致該關(guān)系失效.

假設(shè)當(dāng)前l(fā)ow值是5, high值是10, 當(dāng)線程t獲取lock后, 將low值更新為了15, 此時(shí)被stop了, 真是糟糕, 如果沒有捕獲住stop導(dǎo)致的Error, low的值就為15, high還是10, 這導(dǎo)致它們之間的小于關(guān)系得不到保證, 也就是對(duì)象狀態(tài)被破壞了!

如果在給low賦值的時(shí)候catch住stop導(dǎo)致的Error則可能使后面high變量的賦值繼續(xù), 但是誰也不知道Error會(huì)在哪條語句拋出, 如果對(duì)象狀態(tài)之間的關(guān)系更復(fù)雜呢?這種方式幾乎是無法維護(hù)的, 太復(fù)雜了!如果是中斷操作, 它決計(jì)不會(huì)在執(zhí)行l(wèi)ow賦值的時(shí)候拋出錯(cuò)誤, 這樣程序?qū)τ趯?duì)象狀態(tài)一致性就是可控的.

suspend 與 resume 方法

用來暫停和恢復(fù)線程.

獨(dú)占
public class PrintObject {
    synchronized public void printString(){
        System.out.println("begin");
        if(Thread.currentThread().getName().equals("a")){
            System.out.println("線程 a 被中斷");
            Thread.currentThread().suspend();
        }
        if(Thread.currentThread().getName().equals("b")){
            System.out.println("線程 b 運(yùn)行");
        }
        System.out.println("end");
    }
}
try{
    PrintObject  pb = new PrintObject();
    Thread thread1 = new Thread(pb::printString);
    thread1.setName("a");
    thread1.start();
    thread1.sleep(1000);

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

輸出結(jié)果:

begin
線程 a 被中斷

當(dāng)調(diào)用 Thread.currentThread().suspend(); 方法來暫停線程時(shí), 鎖并不會(huì)被釋放, 所以造成了同步對(duì)象的獨(dú)占.

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/73331.html

相關(guān)文章

  • 初學(xué)者福音!可能是最適合你Java學(xué)習(xí)路線和方法推薦。

    摘要:學(xué)習(xí)完多線程之后可以通過下面這些問題檢測(cè)自己是否掌握,下面這些問題的答案以及常見多線程知識(shí)點(diǎn)的總結(jié)在這里??蛇x數(shù)據(jù)結(jié)構(gòu)與算法如果你想進(jìn)入大廠的話,我推薦你在學(xué)習(xí)完基礎(chǔ)或者多線程之后,就開始每天抽出一點(diǎn)時(shí)間來學(xué)習(xí)算法和數(shù)據(jù)結(jié)構(gòu)。 我自己總結(jié)的Java學(xué)習(xí)的系統(tǒng)知識(shí)點(diǎn)以及面試問題,已經(jīng)開源,目前已經(jīng) 35k+ Star。會(huì)一直完善下去,歡迎建議和指導(dǎo),同時(shí)也歡迎Star: https://...

    yanest 評(píng)論0 收藏0
  • 如何成為一位「不那么差」程序員

    摘要:能理解線程模型多線程優(yōu)缺點(diǎn)以及如何避免。多線程的出現(xiàn)主要是為了提高的利用率任務(wù)的執(zhí)行效率。所以要考慮清楚是否真的需要多線程。這一塊的內(nèi)容可以然我們知道寫大牛處理并發(fā)的思路,對(duì)我們自己編寫高質(zhì)量的多線程程序也有很多幫助。 showImg(https://segmentfault.com/img/remote/1460000015980196?w=2048&h=1363); 前言 已經(jīng)記不...

    caspar 評(píng)論0 收藏0
  • 后端好書閱讀與推薦

    摘要:后端好書閱讀與推薦這一兩年來養(yǎng)成了買書看書的習(xí)慣,陸陸續(xù)續(xù)也買了幾十本書了,但是一直沒有養(yǎng)成一個(gè)天天看書的習(xí)慣。高級(jí)程序設(shè)計(jì)高級(jí)程序設(shè)計(jì)第版豆瓣有人可能會(huì)有疑問,后端為啥要學(xué)呢其實(shí)就是為了更好的使用做鋪墊。 后端好書閱讀與推薦 這一兩年來養(yǎng)成了買書看書的習(xí)慣,陸陸續(xù)續(xù)也買了幾十本書了,但是一直沒有養(yǎng)成一個(gè)天天看書的習(xí)慣。今天突然想要做個(gè)決定:每天至少花1-3小時(shí)用來看書。這里我準(zhǔn)備把這...

    clasnake 評(píng)論0 收藏0
  • 后端好書閱讀與推薦

    摘要:后端好書閱讀與推薦這一兩年來養(yǎng)成了買書看書的習(xí)慣,陸陸續(xù)續(xù)也買了幾十本書了,但是一直沒有養(yǎng)成一個(gè)天天看書的習(xí)慣。高級(jí)程序設(shè)計(jì)高級(jí)程序設(shè)計(jì)第版豆瓣有人可能會(huì)有疑問,后端為啥要學(xué)呢其實(shí)就是為了更好的使用做鋪墊。 后端好書閱讀與推薦 這一兩年來養(yǎng)成了買書看書的習(xí)慣,陸陸續(xù)續(xù)也買了幾十本書了,但是一直沒有養(yǎng)成一個(gè)天天看書的習(xí)慣。今天突然想要做個(gè)決定:每天至少花1-3小時(shí)用來看書。這里我準(zhǔn)備把這...

    Juven 評(píng)論0 收藏0
  • 那些年看過書 —— 致敬大學(xué)生活 —— Say Good Bye !

    摘要:開頭正式開啟我入職的里程,現(xiàn)在已是工作了一個(gè)星期了,這個(gè)星期算是我入職的過渡期,算是知道了學(xué)校生活和工作的差距了,總之,盡快習(xí)慣這種生活吧。當(dāng)時(shí)是看的廖雪峰的博客自己也用做爬蟲寫過幾篇博客,不過有些是在前人的基礎(chǔ)上寫的。 showImg(https://segmentfault.com/img/remote/1460000010867984); 開頭 2017.08.21 正式開啟我...

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

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

0條評(píng)論

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