亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

<jdk7學習筆記>讀書筆記-線程

woshicixide / 2192人閱讀

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

Tread和Runnable 定義線程

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

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

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

主線程會從main()方法開始執(zhí)行,直到main()方法結(jié)束后停止jvm.如果主線程中啟動了額外線程,則主線程默認會等到被啟動的所有額外線程都執(zhí)行完run()方法才會終止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
...

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

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

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

在一個時間點上,一個cpu只能執(zhí)行一個線程,只是cpu會不斷切換線程??梢杂肨hread的setPriority()方法設(shè)置線程的優(yōu)先級,設(shè)定值1-10,默認為5.優(yōu)先級越高的線程,越有機會搶占cpu.
線程進入blocked狀態(tài)可能的情況:

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

進入synchronized前,對競爭對象的鎖定

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

等待io完成

...

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

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

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

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

使用join()

public class Daemon implements Runnable{
    @Override
    public void run() {
        System.out.println("線程開始");
        try {
            Thread.sleep(3000);
            System.out.println("線程執(zhí)行");
        } catch (InterruptedException e) {
            System.out.println("離開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("主線程開始");
    }
}
線程開始
線程執(zhí)行
線程結(jié)束
主線程開始

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

停止線程

線程完成run()方法后,就進入dead狀態(tài)。這時不能再次調(diào)用start()方法。
Thread類上的stop()方法是過時方法。
如果要停止線程,最好自行操作,讓線程跑完應(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){...}

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

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

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

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

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

在兩個synchronized區(qū)塊里,沒有公共的數(shù)據(jù),方法。當有一個線程執(zhí)行method1()而另一個線程執(zhí)行method2()時,并不會引起共享存取問題,而且一個線程不會因為另一個線程獲得鎖定而阻塞.
java的synchronized提供的是可重入同步,也就是線程獲得某對象鎖定后,若執(zhí)行過程中又要執(zhí)行synchronized,而這個鎖定對象的來源又和前面的是同一個,則可以直接執(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)死鎖,也可能不會。
如果出現(xiàn)的話,原因在于

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

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

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

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

volatile

synchronized所標志區(qū)塊的特點:

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

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

在java中對于可見性的要求,可以使用volatile達到變量范圍。
沒用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,甚至可以遠大于i.原因在于為了效率,線程可以快取變量的值。
t2調(diào)用Variable.print()從共享內(nèi)存中取到變量i的值,并存儲在自己的內(nèi)存空間,如果此時cpu切換線程至t1,并不斷的執(zhí)行Variable.deal()多次,再切回t2,取得變量j的值,然后和i值一起輸出。

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

在變量上聲明volatile,表示變量是不穩(wěn)定的,易變的。這樣變量就可以在多線程情況下存取,保證了變量的可見性.換句話說,如果有線程修改了變量的值,另一個線程一定可以看到被修改的變量。
被標示為volatile的變量,不允許線程快取,變量的存取一定是在共享內(nèi)存中進行。
下面將上面例子中的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遠大于i的情況,都是i略小于j.
事實上,ij的關(guān)系可以是大于,等于,小于三種之中的任一種。

i大于j

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

i小于j

第一次輸出時,保存i,然后j++,第二次輸出的是沒有修改過的i和修改過的j.

i等于j

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

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

等待與通知

wait(),notify(),notifyAll()是Object類中的方法,可以通過這三個方法控制線程釋放對象的鎖定,或者通知線程參與鎖定的競爭.

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

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

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/64706.html

相關(guān)文章

  • &lt;jdk7學習筆記&gt;讀書筆記-并行api

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

    bovenson 評論0 收藏0
  • 《HTML與CSS 第一章 認識HTML》讀書筆記

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

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

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

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

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

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

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

    William_Sang 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<