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

資訊專欄INFORMATION COLUMN

<jdk7學(xué)習(xí)筆記>讀書(shū)筆記-線程

woshicixide / 2145人閱讀

摘要:如果把注釋去掉,則在所以非線程都結(jié)束時(shí),自動(dòng)終止。默認(rèn)所有從線程產(chǎn)生的線程也是線程。停止線程線程完成方法后,就進(jìn)入狀態(tài)。被標(biāo)示為的區(qū)塊會(huì)被監(jiān)控,任何線程要執(zhí)行區(qū)塊都必須先獲得指定的對(duì)象鎖定。

Tread和Runnable 定義線程

實(shí)現(xiàn)Runnable接口,重寫(xiě)run()方法

繼承Thread類,重寫(xiě)run()方法

啟動(dòng)線程
        Runnable tortoise=new Tortoise();
        Thread thread1=new Thread(tortoise);
        thread1.start();
        Thread thread1=new Tortoise();
        thread1.start();
線程生命周期 daemon線程

主線程會(huì)從main()方法開(kāi)始執(zhí)行,直到main()方法結(jié)束后停止jvm.如果主線程中啟動(dòng)了額外線程,則主線程默認(rèn)會(huì)等到被啟動(dòng)的所有額外線程都執(zhí)行完run()方法才會(huì)終止jvm.

public class Daemon implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("TheViper");
        }
    }
    public static void main(String[] args){
        Thread thread=new Thread(new Daemon());
        //thread.setDaemon(true);
        thread.start();
    }
}
TheViper
TheViper
TheViper
...

控制臺(tái)會(huì)不停的打印。如果把注釋去掉,thread.setDaemon(true),則在所以非daemon線程都結(jié)束時(shí),jvm自動(dòng)終止。
默認(rèn)所有從daemon線程產(chǎn)生的線程也是daemon線程。

線程基本狀態(tài)圖

啟動(dòng)線程后,基本狀態(tài)可分為可執(zhí)行(runnable),阻塞(blocked),執(zhí)行中(running).

在一個(gè)時(shí)間點(diǎn)上,一個(gè)cpu只能執(zhí)行一個(gè)線程,只是cpu會(huì)不斷切換線程。可以用Thread的setPriority()方法設(shè)置線程的優(yōu)先級(jí),設(shè)定值1-10,默認(rèn)為5.優(yōu)先級(jí)越高的線程,越有機(jī)會(huì)搶占cpu.
線程進(jìn)入blocked狀態(tài)可能的情況:

調(diào)用Thread.sleep()方法

進(jìn)入synchronized前,對(duì)競(jìng)爭(zhēng)對(duì)象的鎖定

調(diào)用wait()方法阻斷

等待io完成

...

一個(gè)處于blocked狀態(tài)的線程,可由另一個(gè)線程調(diào)用interrupt()方法,讓它離開(kāi)blocked狀態(tài)。

public class Daemon implements Runnable{
    @Override
    public void run() {
        System.out.println("TheViper");
        try {
            Thread.sleep(3000);//進(jìn)入blocked狀態(tài)
        } catch (InterruptedException e) {
            System.out.println("離開(kāi)blocked狀態(tài)");
        }
    }
    public static void main(String[] args){
        Thread thread=new Thread(new Daemon());
        thread.start();
        thread.interrupt();
    }
}
TheViper
離開(kāi)blocked狀態(tài)
安插線程

假設(shè)線程A正在運(yùn)行,這時(shí)線程B想占用cpu運(yùn)行,等它運(yùn)行完后,繼續(xù)運(yùn)行線程A.這種情況可以使用join()方法.
未使用join()

public class Daemon implements Runnable{
    @Override
    public void run() {
        System.out.println("線程開(kāi)始");
        try {
            Thread.sleep(3000);
            System.out.println("線程執(zhí)行");
        } catch (InterruptedException e) {
            System.out.println("離開(kāi)blocked狀態(tài)");
        }
        System.out.println("線程結(jié)束");
    }
    public static void main(String[] args){
        Thread thread=new Thread(new Daemon());
        thread.start();
        System.out.println("主線程開(kāi)始");
    }
}
主線程開(kāi)始
線程開(kāi)始
線程執(zhí)行
線程結(jié)束

使用join()

public class Daemon implements Runnable{
    @Override
    public void run() {
        System.out.println("線程開(kāi)始");
        try {
            Thread.sleep(3000);
            System.out.println("線程執(zhí)行");
        } catch (InterruptedException e) {
            System.out.println("離開(kāi)blocked狀態(tài)");
        }
        System.out.println("線程結(jié)束");
    }
    public static void main(String[] args) throws InterruptedException{
        Thread thread=new Thread(new Daemon());
        thread.start();
        thread.join();
        System.out.println("主線程開(kāi)始");
    }
}
線程開(kāi)始
線程執(zhí)行
線程結(jié)束
主線程開(kāi)始

程序啟動(dòng)后就開(kāi)始運(yùn)行主線程(因?yàn)樾陆ň€程使用了sleep(),讓新建線程進(jìn)入blocked狀態(tài),主線程可以占用cpu),對(duì)新建的線程使用join(),將其加入到主線程后,原本應(yīng)該一來(lái)就運(yùn)行的主線程,現(xiàn)在需要等到后面新建的線程執(zhí)行完后,才能繼續(xù)執(zhí)行。
如果加入的線程處理時(shí)間太久,可以在join()時(shí)指定時(shí)間,如join(10000),表示加入的線程最多只能處理10秒。

停止線程

線程完成run()方法后,就進(jìn)入dead狀態(tài)。這時(shí)不能再次調(diào)用start()方法。
Thread類上的stop()方法是過(guò)時(shí)方法。
如果要停止線程,最好自行操作,讓線程跑完應(yīng)有的流程,而不是調(diào)用stop()方法

...
private boolean isContinue=true;
public void stop(){
    this.isContinue=false;
}
public void run(){
    while(isContinue){
        ...
    }
}
...
synchronized
public synchronized void add(Object o){...}

每個(gè)對(duì)象都有一個(gè)內(nèi)部鎖定。被標(biāo)示為synchronized的區(qū)塊會(huì)被監(jiān)控,任何線程要執(zhí)行synchronized區(qū)塊都必須先獲得指定的對(duì)象鎖定。
如果線程A已獲得對(duì)象鎖定開(kāi)始執(zhí)行sychronized區(qū)塊,線程B也想執(zhí)行synchronized區(qū)塊,線程B會(huì)因?yàn)闊o(wú)法獲得對(duì)象鎖定而進(jìn)入等待對(duì)象鎖定狀態(tài),直到線程A釋放鎖定(如執(zhí)行完synchronized區(qū)塊)。
在方法上標(biāo)示sychronized,則執(zhí)行方法必須獲得該實(shí)例的指定。
實(shí)際上等待對(duì)象鎖定時(shí),也會(huì)進(jìn)入線程的blocked狀態(tài)

synchronized不僅可以聲明在方法上,也可以描述句方式使用

public void add(Object o){
    synchronized(this){
        ...
    }
}
List list=new ArrayList();
synchronized(list){
    ...
    list.add("TheViper");//讓ArrayList線程安全
}

這種方式不用鎖定整個(gè)方法,只鎖定會(huì)發(fā)生競(jìng)爭(zhēng)狀況的區(qū)塊。獲得鎖定的線程執(zhí)行完這個(gè)區(qū)塊后,會(huì)立即釋放鎖定,其他線程就有機(jī)會(huì)再競(jìng)爭(zhēng)這個(gè)鎖定.
相比于將整個(gè)方法聲明為synchronized,這種方式更有效率。
可以提供不同的對(duì)象作為鎖定的來(lái)源

private Object lock1=new Object();
private Object lock2=new Object();
public void method1(){
    synchronized(lock1){
        data1++;
        ...
    }
}
public void method2(){
    synchronized(lock2){
        data2++;
        ...
    }
}

在兩個(gè)synchronized區(qū)塊里,沒(méi)有公共的數(shù)據(jù),方法。當(dāng)有一個(gè)線程執(zhí)行method1()而另一個(gè)線程執(zhí)行method2()時(shí),并不會(huì)引起共享存取問(wèn)題,而且一個(gè)線程不會(huì)因?yàn)榱硪粋€(gè)線程獲得鎖定而阻塞.
java的synchronized提供的是可重入同步,也就是線程獲得某對(duì)象鎖定后,若執(zhí)行過(guò)程中又要執(zhí)行synchronized,而這個(gè)鎖定對(duì)象的來(lái)源又和前面的是同一個(gè),則可以直接執(zhí)行。

死鎖
public class Resource {
    synchronized void doSome(){
        
    }
    public synchronized void deal(Resource res){
        res.doSome();
    }
}
public class TheadDemo extends Thread{
    Resource res1;
    Resource res2;
    TheadDemo(Resource res1,Resource res2){
        this.res1=res1;
        this.res2=res2;
    }
    @Override
    public void run(){
        for(int i=0;i<10;i++)
            this.res1.deal(this.res2);
    }
    public static void main(String[] args){
        Resource res1=new Resource();
        Resource res2=new Resource();
        Thread thread1=new TheadDemo(res1,res2);
        Thread thread2=new TheadDemo(res2,res1);
        thread1.start();
        thread2.start();
    }
}

這段代碼可能出現(xiàn)死鎖,也可能不會(huì)。
如果出現(xiàn)的話,原因在于

Thread thread1=new TheadDemo(res1,res2)=>this.res1.deal(this.res2)時(shí),thread1獲得res1的鎖定

Thread thread2=new TheadDemo(res2,res1)=>this.res2.deal(this.res1),thread2獲得res2的鎖定

thread1線程res2.doSome(),準(zhǔn)備獲得res2的鎖定,但是res2的鎖定被thread2線程占用,于是thread1線程進(jìn)入blocked狀態(tài)

thread2線程res1.doSome(),準(zhǔn)備獲得res1的鎖定,但是res1的鎖定被thread1線程占用,于是thread2線程進(jìn)入blocked狀態(tài)

volatile

synchronized所標(biāo)志區(qū)塊的特點(diǎn):

互斥性:synchronized區(qū)塊在一個(gè)時(shí)間點(diǎn)上只能有一個(gè)線程執(zhí)行它

可見(jiàn)性:線程離開(kāi)synchronized區(qū)塊后,另一個(gè)線程面對(duì)的是上一個(gè)線程改變后的對(duì)象狀態(tài)

在java中對(duì)于可見(jiàn)性的要求,可以使用volatile達(dá)到變量范圍。
沒(méi)用volatile,synchronized

public class Variable {
    static int i=0,j=0;
    static void deal(){
        i++;
        j++;
    }
    static void print(){
        System.out.println("i="+i+" j="+j);
    }
}
public class VariableTest1 extends Thread{
    @Override
    public void run(){
        while(true)
            Variable.print();
    }
}
public class VariableTest extends Thread{
    @Override
    public void run(){
        while(true)
            Variable.deal();
    }
    public static void main(String[] args){
        Thread t1=new VariableTest();
        Thread t2=new VariableTest1();
        t1.start();
        t2.start();
    }
}
...
i=638864948 j=638864993
i=638866963 j=638867006
i=638868897 j=638868941
i=638870928 j=638870974
...

可以看到j(luò)大于i,甚至可以遠(yuǎn)大于i.原因在于為了效率,線程可以快取變量的值。
t2調(diào)用Variable.print()從共享內(nèi)存中取到變量i的值,并存儲(chǔ)在自己的內(nèi)存空間,如果此時(shí)cpu切換線程至t1,并不斷的執(zhí)行Variable.deal()多次,再切回t2,取得變量j的值,然后和i值一起輸出。

如果在deal()和print()方法上標(biāo)志synchronized,則t1每次調(diào)用deal()方法時(shí),t2都必須等到t1釋放鎖定才能調(diào)用print()方法.t2每次調(diào)用print()方法也一樣。
這種情況下,輸出的i一定等于j.

在變量上聲明volatile,表示變量是不穩(wěn)定的,易變的。這樣變量就可以在多線程情況下存取,保證了變量的可見(jiàn)性.換句話說(shuō),如果有線程修改了變量的值,另一個(gè)線程一定可以看到被修改的變量。
被標(biāo)示為volatile的變量,不允許線程快取,變量的存取一定是在共享內(nèi)存中進(jìn)行。
下面將上面例子中的i,j聲明為volatile.

volatile static int i=0,j=0;
...
i=34456445 j=34456448
i=34456620 j=34456623
i=34456789 j=34456791
i=34456959 j=34456961
...

可以看到?jīng)]有出現(xiàn)j遠(yuǎn)大于i的情況,都是i略小于j.
事實(shí)上,ij的關(guān)系可以是大于,等于,小于三種之中的任一種。

i大于j

i已經(jīng)改變,但是j仍然是上一次操作的j.

i小于j

第一次輸出時(shí),保存i,然后j++,第二次輸出的是沒(méi)有修改過(guò)的i和修改過(guò)的j.

i等于j

輸出的都是共享內(nèi)存中修改過(guò)的值.

由此可見(jiàn),volatile保證的是單一變量可見(jiàn)性,線程對(duì)變量的存取一定是在共享內(nèi)存中進(jìn)行,不會(huì)在自己的內(nèi)存空間中快取變量。線程對(duì)共享內(nèi)存中變量的存取,另一個(gè)線程一定看得到。

等待與通知

wait(),notify(),notifyAll()是Object類中的方法,可以通過(guò)這三個(gè)方法控制線程釋放對(duì)象的鎖定,或者通知線程參與鎖定的競(jìng)爭(zhēng).

線程進(jìn)入synchronized區(qū)塊前,要先獲得指定對(duì)象的鎖定。而在執(zhí)行synchronized區(qū)塊代碼時(shí),若調(diào)用鎖定對(duì)象的wait()方法,線程會(huì)釋放對(duì)象鎖定,并進(jìn)入對(duì)象等待集合,其他線程這時(shí)可以競(jìng)爭(zhēng)對(duì)象鎖定,取得鎖定的線程可以執(zhí)行synchronized區(qū)塊代碼。
處于等待集合中的線程不會(huì)參與競(jìng)爭(zhēng)cpu.wait()方法可以指定等待時(shí)間,時(shí)間到之后,線程會(huì)參與競(jìng)爭(zhēng)cpu.如果指定時(shí)間為0或沒(méi)指定,則線程會(huì)一直等待,直到被中斷(interrupt)或通知(notify)可以參與競(jìng)爭(zhēng)cpu.
鎖定的對(duì)象調(diào)用notify()方法,會(huì)對(duì)象等待集合中隨機(jī)通知一個(gè)線程參與競(jìng)爭(zhēng)cpu.
如果調(diào)用的是notifyAll()方法,則等待集合中的所有線程都會(huì)參與競(jìng)爭(zhēng)cpu.

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

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

相關(guān)文章

  • &lt;jdk7學(xué)習(xí)筆記&gt;讀書(shū)筆記-并行api

    摘要:然而,這兩個(gè)方法都只是讀取對(duì)象狀態(tài),如果只是讀取操作,就可以允許線程并行,這樣讀取效率將會(huì)提高。分配線程執(zhí)行子任務(wù)執(zhí)行子任務(wù)獲得子任務(wù)進(jìn)行完成的結(jié)果 Lock Lock接口主要操作類是ReentrantLock,可以起到synchronized的作用,另外也提供額外的功能。用Lock重寫(xiě)上一篇中的死鎖例子 import java.util.concurrent.locks.Lock; ...

    bovenson 評(píng)論0 收藏0
  • 《HTML與CSS 第一章 認(rèn)識(shí)HTML》讀書(shū)筆記

    摘要:一讓廣播明星黯然失色要建立頁(yè)面,需要?jiǎng)?chuàng)建用超文本標(biāo)記語(yǔ)言,編寫(xiě)的文件,把它們放在一個(gè)服務(wù)器上二服務(wù)器能做什么服務(wù)器在互聯(lián)網(wǎng)上有一份全天候的工作。一、Web讓廣播明星黯然失色    要建立Web頁(yè)面,需要?jiǎng)?chuàng)建用超文本標(biāo)記語(yǔ)言(HyperText Markup Language,HTML)編寫(xiě)的文件,把它們放在一個(gè)Web服務(wù)器上二、Web服務(wù)器能做什么?  Web服務(wù)器在互聯(lián)網(wǎng)上有一份全天候的工...

    番茄西紅柿 評(píng)論0 收藏0
  • &lt;javascript高級(jí)程序設(shè)計(jì)&gt;第十二章讀書(shū)筆記----偏移量

    摘要:包括元素的高度上下內(nèi)邊距上下邊框值,如果元素的的值為那么該值為。該值為元素的包含元素。最后,所有這些偏移量都是只讀的,而且每次訪問(wèn)他們都需要重新計(jì)算。為了避免重復(fù)計(jì)算,可以將計(jì)算的值保存起來(lái),以提高性能。 offsetHeight 包括元素的高度、上下內(nèi)邊距、上下邊框值,如果元素的style.display的值為none,那么該值為0。offsetWidth 包括元素的寬度、左...

    dayday_up 評(píng)論0 收藏0
  • &lt;java核心技術(shù)&gt;讀書(shū)筆記2

    摘要:如果需要收集參數(shù)化類型對(duì)象,只有使用警告這節(jié)討論,向參數(shù)可變的方法傳遞一個(gè)泛型類型的實(shí)例。異常不能拋出或捕獲泛型類的實(shí)例實(shí)際上,泛型類擴(kuò)展也是不合法的。 Object:所有類的超類 java中每個(gè)類都是由它擴(kuò)展而來(lái),但是并不需要這樣寫(xiě):class Employee extends Object.如果沒(méi)有明確指出超類,Object類就被認(rèn)為是這個(gè)的超類??梢允褂肙bject類型的變量引用...

    jimhs 評(píng)論0 收藏0
  • &lt;java核心技術(shù)&gt;讀書(shū)筆記1

    摘要:關(guān)鍵字作用調(diào)用超類方法調(diào)用超類構(gòu)造器關(guān)鍵字作用引用隱式參數(shù)如調(diào)用該類的其他構(gòu)造器在覆蓋一個(gè)方法時(shí),子類方法可見(jiàn)性不能低于超類方法阻止繼承類和方法目的確保它們不會(huì)在子類中改變語(yǔ)義。但是如果將一個(gè)類聲明為后面可以改變類變量的值了。 數(shù)據(jù)類型 整型 int 存儲(chǔ)要求:4byte 取值范圍:-2147483648 -- 2147483647(超過(guò)20億) short 存儲(chǔ)要求:2byte 取...

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

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

0條評(píng)論

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