中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java多線程是什么意思

發布時間:2021-08-26 14:15:31 來源:億速云 閱讀:291 作者:chen 欄目:編程語言

這篇文章主要講解了“Java多線程是什么意思”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Java多線程是什么意思”吧!

多線程(multiple thread)是計算機實現多任務并行處理的一種方式。

在單線程情況下,計算機中存在一個控制權,并按照順序依次執行指令。單線程好像是一個只有一個隊長指揮的小隊,整個小隊同一個時間只能執行一個任務。

單線程

在多線程情境下,計算機中有多個控制權。多個控制權可以同時進行,每個控制權依次執行一系列的指令。多線程好像是一個小隊中的成員同時執行不同的任務。

可參考 Linux多線程與同步,并對比 Python多線程與同步

多線程

傳統意義上,多線程是由操作系統提供的功能。對于單核的CPU,硬件中只存在一個線程。在操作系統的控制下,CPU會在不同的任務間(線程間)切換,從而造成多任務齊頭并進的效果。這是單CPU分時復用機制下的多線程。現在,隨著新的硬件技術的發展,硬件本身開始提供多線程支持,比如多核和超線程技術。然而,硬件的多線程還是要接受操作系統的統一管理。在操作系統之上的多線程程序依然通用。

多個線程可以并存于同一個進程空間。在JVM的一個進程空間中,一個棧(stack)代表了方法調用的次序。對于多線程來說,進程空間中需要有多個棧,以記錄不同線程的調用次序。多個棧互不影響,但所有的線程將共享堆(heap)中的對象。

創建線程

Java中“一切皆對象”,線程也被封裝成一個對象。我們可以通過繼承Thread類來創建線程。線程類中的的run()方法包含了該線程應該執行的指令。我們在衍生類中覆蓋該方法,以便向線程說明要做的任務:

public class Test
{    public static void main(String[] args)
    {
        NewThread thread1 = new NewThread();
        NewThread thread2 = new NewThread();
        thread1.start(); // start thread1
        thread2.start(); // start thread2    }
}/**
 * create new thread by inheriting Thread */class NewThread extends Thread {    private static int threadID = 0; // shared by all
    /**
     * constructor     */
    public NewThread() {        super("ID:" + (++threadID));
    }    /**
     * convert object to string     */
    public String toString() {        return super.getName();
    }    /**
     * what does the thread do?     */
    public void run() {
        System.out.println(this);
    }
}

(++是Java中的累加運算符,即讓變量加1。這里++出現在threadID之前,說明先將threadID加1,再對周邊的表達式求值

toString是Object根類的方法,我們通過覆蓋該方法,來將對象轉換成字符串。當我們打印該對象時,Java將自動調用該方法。)

可以看到,Thread基類的構建方法(super())可以接收一個字符串作為參數。該字符串是該線程的名字,并使用getName()返回。

定義類之后,我們在main()方法中創建線程對象。每個線程對象為一個線程。創建線程對象后,線程還沒有開始執行。

我們調用線程對象的start()方法來啟動線程。start()方法可以在構造方法中調用。這樣,我們一旦使用new創建線程對象,就立即執行。

Thread類還提供了下面常用方法:

join(Thread tr)   等待線程tr完成

setDaemon()       設置當前線程為后臺daemon (進程結束不受daemon線程的影響)

Thread類官方文檔:  http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.html

Runnable

實現多線程的另一個方式是實施Runnable接口,并提供run()方法。實施接口的好處是容易實現多重繼承(multiple inheritance)。然而,由于內部類語法,繼承Thread創建線程可以實現類似的功能。我們在下面給出一個簡單的例子,而不深入:

public class Test
{    public static void main(String[] args)
    {
        Thread thread1 = new Thread(new NewThread(), "first");
        Thread thread2 = new Thread(new NewThread(), "second");
        thread1.start(); // start thread1
        thread2.start(); // start thread2    }
}/**
 * create new thread by implementing Runnable */class NewThread implements Runnable {    /**
     * convert object to string     */
    public String toString() {        return Thread.currentThread().getName();
    }    /**
     * what does the thread do?     */
    public void run() {
        System.out.println(this);
    }
}

synchronized

多任務編程的難點在于多任務共享資源。對于同一個進程空間中的多個線程來說,它們都共享堆中的對象。某個線程對對象的操作,將影響到其它的線程。

在多線程編程中,要盡力避免競爭條件(racing condition),即運行結果依賴于不同線程執行的先后。線程是并發執行的,無法確定線程的先后,所以我們的程序中不應該出現競爭條件。

然而,當多任務共享資源時,就很容易造成競爭條件。我們需要將共享資源,并造成競爭條件的多個線程線性化執行,即同一時間只允許一個線程執行。

(可更多參考 Linux多線程與同步)

下面是一個售票程序。3個售票亭(Booth)共同售賣100張票(Reservoir)。每個售票亭要先判斷是否有余票,然后再賣出一張票。如果只剩下一張票,在一個售票亭的判斷和售出兩個動作之間,另一個售票亭賣出該票,那么第一個售票亭(由于已經執行過判斷)依然會齒形賣出,造成票的超賣。為了解決該問題,判斷和售出兩個動作之間不能有“空隙”。也就是說,在一個線程完成了這兩個動作之后,才能有另一個線程執行。

在Java中,我們將共享的資源置于一個對象中,比如下面r(Reservoir)對象。它包含了總共的票數;將可能造成競爭條件的,針對共享資源的操作,放在synchronized(同步)方法中,比如下面的sellTicket()。synchronized是方法的修飾符。在Java中,同一對象的synchronized方法只能同時被一個線程調用。其他線程必須等待該線程調用結束,(余下的線程之一)才能運行。這樣,我們就排除了競爭條件的可能。

在main()方法中,我們將共享的資源(r對象)傳遞給多個線程:

public class Test
{    public static void main(String[] args)
    {
        Reservoir r = 
new Reservoir(100);
        Booth b1 = 
new Booth(r);
        Booth b2 = 
new Booth(r);
        Booth b3 = 
new Booth(r);
    }
}/**
 * contain shared resource
 */class Reservoir {    private int total;    public Reservoir(int t) 
    {        this.total = t;
    }    /**
     * Thread safe method
     * serialized access to Booth.total     */
    public synchronized boolean sellTicket() 
    {        if(this.total > 0) {            this.total = 
this.total - 1;            return true; 
// successfully sell one        }        else {            return false; 
// no more tickets        }
    }
}/**
 * create new thread by inheriting Thread */class Booth 
extends Thread {    private static int threadID = 0; 
// owned by Class object
    private Reservoir release;      // sell this reservoir 
    private int count = 0;          // owned by this thread object
    /**
     * constructor     */
    public Booth(Reservoir r) {        super("ID:" + (++threadID));        this.release = r;          // all threads share the same reservoir
        this.start();
    }    /**
     * convert object to string     */
    public String toString() {        return super.getName();
    }    /**
     * what does the thread do?     */
    public void run() {        while(true) {            if(this.release.sellTicket()) {                this.count = 
this.count + 1;
                System.out.println(this.getName() + ": sell 1");                try {
                    sleep((int) Math.random()*100);   
// random intervals                }                catch (InterruptedException e) {                    throw new RuntimeException(e);
                }
            }            else {                break;
            }
        }
        System.out.println(this.getName() + " I sold:" + count);
    }
}

(Math.random()用于產生隨機數)

Java的每個對象都自動包含有一個用于支持同步的計數器,記錄synchronized方法的調用次數。線程獲得該計數器,計數器加1,并執行synchronized方法。如果方法內部進一步調用了該對象的其他synchronized方法,計數器加1。當synchronized方法調用結束并退出時,計數器減1。其他線程如果也調用了同一對象的synchronized方法,必須等待該計數器變為0,才能鎖定該計數器,開始執行。Java中的類同樣也是對象( Class類對象)。Class類對象也包含有計數器,用于同步。

關鍵代碼

上面,我們利用synchronized修飾符同步了整個方法。我們可以同步部分代碼,而不是整個方法。這樣的代碼被稱為關鍵代碼(critical section)。我們使用下面的語法:

synchronized (syncObj) {
  ...;
}

花括號中包含的是想要同步的代碼,syncObj是任意對象。我們將使用syncObj對象中的計數器,來同步花括號中的代碼。

感謝各位的閱讀,以上就是“Java多線程是什么意思”的內容了,經過本文的學習后,相信大家對Java多線程是什么意思這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

金溪县| 漯河市| 遵义县| 绥宁县| 梅河口市| 无锡市| 苍溪县| 塘沽区| 岚皋县| 阿荣旗| 安徽省| 鲁山县| 紫金县| 波密县| 湟中县| 望都县| 太保市| 宁河县| 保亭| 孟连| 景谷| 邻水| 旌德县| 山东省| 师宗县| 浙江省| 电白县| 温宿县| 收藏| 西乌珠穆沁旗| 张家界市| 合作市| 鄂托克前旗| 贡觉县| 萨迦县| 皋兰县| 太和县| 三河市| 九龙城区| 响水县| 正定县|