Java筆記:多線程

來源:互聯網
上載者:User

標籤:擴充   tar   多線程   public   priority   訪問   sleep   休眠   意義   

一、意義

使用多線程的目的是為了提高CPU資源的利用效率。在單線程應用中程式必須等待當前任務的完成才能繼續執行下一項任務,CPU在等待的時間內就閑置了,多線程的使用可減少閑置時間。

 

二、主線程

當Java程式啟動時,會立即開始運行主線程。其他所有的線程都是從主線程產生的,主線程必須是最後才結束執行的線程,因為它需要執行各種關閉動作。可以通過currentThread靜態方法擷取主線程的引用。

class Solution {    public static void main(String[] args) {        Thread t = Thread.currentThread();        System.out.println("Current thread: " + t);//Thread[main,5,main]        try {            for (int i = 0; i < 10; i++) {                System.out.println(i);                Thread.sleep(500);            }        } catch (InterruptedException exc) {            System.out.println("Current thread interrupted");        }    }}

預設情況下,主線程的名字是main,優先順序是5,main也是主線程所屬的線程組的名字。線程組是將線程作為一個整體來控制狀態的資料結構。

 

三、建立線程

可通過繼承Thread類或實現Runnable介面來建立線程。

實現Runnable介面建立線程時,只需要實現run方法,run方法定義線程的代碼,線程隨run方法結束而結束。在建立了新線程之後,只有調用start方法線程才會運行,本質上start方法執行對run方法的調用。但是Runnable介面只定義了run方法,執行run類的代碼必須藉助Thread執行個體。

擴充Thread類建立線程時, 必須重寫run方法或定義Runnable介面執行個體。

class ThreadA extends Thread {    @Override    public void run() {        try {            for (int i = 0; i < 10; i++) {                System.out.println(i);                Thread.sleep(500);            }        } catch (InterruptedException exc) {            System.out.println(getName() + " interrupted");        }    }    ThreadA(String name) {        super(name);        start();    }}class ThreadB implements Runnable {    private Thread t;    @Override    public void run() {        try {            for (int i = 0; i < 10; i++) {                System.out.println(i);                Thread.sleep(500);            }        } catch (InterruptedException exc) {            System.out.println(t.getName() + " interrupted");        }    }    ThreadB(String name) {        t = new Thread(this, name);        t.start();    }}class Solution {    public static void main(String[] args) {        ThreadA tA = new ThreadA("A");        ThreadB tB = new ThreadB("B");    }}

 

四、等待線程

當某個線程需要耗費大量時間運算,而其他線程又需要等待該線程結束後才能繼續擷取資料。這種情況下可直接調用該線程的join方法,程式會停留於調用join方法處直至調用該方法的線程結束才會繼續執行後面的代碼。

class MyThread extends Thread {    @Override    public void run() {        try {            for (int i = 0; i < 10; i++) {                System.out.println(i);                Thread.sleep(500);            }        } catch (InterruptedException exc) {            System.out.println(getName() + " interrupted");        }    }    MyThread(String name) {        super(name);    }}class Solution {    public static void main(String[] args) {        MyThread tA = new MyThread("thread A");        MyThread tB = new MyThread("thread B");        MyThread tC = new MyThread("thread C");        try {            tA.start();            tA.join();//停留直至tA結束            tB.start();            tB.join(1000);//停留1秒後無論tB是否結束都繼續執行後面的代碼            tC.start();            tC.join();//停留直至tC結束        } catch (InterruptedException exc) {            System.out.println("Thread interrupted");        }        System.out.println("Thread A is alive " + tA.isAlive());        System.out.println("Thread B is alive " + tB.isAlive());        System.out.println("Thread C is alive " + tC.isAlive());    }}

 

五、優先順序

Java為線程指定了優先順序,優先順序決定了相對於其他線程會如何處理某個線程。優先順序是整數,但絕對值沒有意義。線程的優先順序必須在MIN_PRIORITY到MAX_PRIORITY之間,線上程中是作為靜態常量定義的。優先順序決定何時從一個啟動並執行線程切換到下一個,稱為環境切換。發生規則如下:

  • 線程自願放棄控制。線程顯式放棄控制權、休眠或再I/O之前阻塞,都會導致這種情況的出現。發生這種情況時,會檢查其他線程,並且即將啟動並執行線程中優先順序最高的會獲得CPU資源。
  • 線程被優先順序更高的線程取代。沒有放棄控制權的低優先順序線程無論在做什麼,都會被高優先順序的線程取代。只要高優先順序線程運行,就會取代低優先順序線程,稱為搶佔式多任務處理。

具有相同優先順序的線程競爭CPU資源時,Windows中會以迴圈的方式自動獲得CPU資源,其他動作系統中優先順序相等的線程必須主動放棄控制權其他線程才能運行。理論上優先順序更高的線程會獲得更多的CPU時間,具有相同優先順序的線程應當得到相同的CPU時間,但不同環境的多任務方式不同,為了安全起見,具有相同優先順序的線程應當時不時放棄控制權,以確保所有線程在非搶佔式作業系統中有機會運行。

 

六、同步

多線程使程式可以進行非同步行為,所以必須提供一種在需要時強制同步的方法。例如當兩個線程進行通訊並共用某個複雜的資料結構,當一個線程向資料結構中寫入資料時,必須阻止其他線程向資料結構中寫入資料,否則可能會發生衝突。

同步的關鍵是監視器,監視器是用作互斥鎖的對象。在給定時刻只有一個線程可以擁有監視器,一旦線程進入監視器,也就是取得鎖,其他所有線程就必須等待,直至該線程退出監視器,其他所有嘗試進入加鎖監視器的線程都會被掛起。Java中每個類都有自己隱式的監視器,每當對象的同步方法被調用時,線程就會自動進入對象的隱式監視器。

class Callme {    synchronized void call(String msg) {//同步方法        System.out.print("[" + msg);        try {            Thread.sleep(1000);            System.out.println("]");        } catch (InterruptedException exc) {            System.out.println("Callme interrupted");        }    }}class Caller extends Thread {    private String msg;    private Callme target;    Caller(Callme target, String msg) {        this.target = target;        this.msg = msg;        start();    }    @Override    public void run() {        target.call(msg);    }}class Solution {    public static void main(String[] args) {        Callme target = new Callme();        Caller obA = new Caller(target, "Caller A");        Caller obB = new Caller(target, "Caller B");        Caller obC = new Caller(target, "Caller C");        try {            obA.join();            obB.join();            obC.join();        } catch (InterruptedException exc) {            System.out.println("Caller interrupted");        }    }}

但是假設某個類並沒有對多線程進行設計,即類中沒有同步方法。由於我們並不是該類的建立者,無法訪問其原始碼,也就無法使用上述方法為類中的方法添加synchronized修飾符。那麼可以將需要同步的部分放到synchronized代碼塊中。

class Caller extends Thread {    private String msg;    private Callme target;    Caller(Callme target, String msg) {        this.target = target;        this.msg = msg;        start();    }    @Override    public void run() {        synchronized (target) {//同步代碼塊            target.call(msg);        }    }}

 

Java筆記:多線程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.