JAVA多線程之Thread&&Runnable 樣本

來源:互聯網
上載者:User

看了個視頻,嗯,記錄下加深下理解。。。java實現多線程的兩種方式:繼承thread類,這種方式的缺陷就是java的單繼承導致的;還有一種方式就是實現Runnable介面,這種方式避免了thread方式由於java單繼承帶來的缺陷。需要知道的是線程啟動後會搶佔CPU資源,如果當前new了一個線程,線程就會進入建立的狀態,然後我們啟動這個線程,thread.start(),這個時候這個線程就會處在就緒狀態,如果當前能擷取到CPU資源,然後就會處在運行狀態,如果這個時候執行了sleep方法或者一些阻塞事件,會導致線程處於阻塞狀態,然後sleep到一定時間後阻塞解除,會繼續排隊到就緒狀態,繼續等待當前釋放CPU釋放資源,如果run方法執行完畢的話,那麼線程終止,自動銷毀。這也是為什麼不加synchronized的話會出現亂序的情況。因為你雖然進入了線程隊列,但是當前cpu資源不一定是被你獲得了,會被後來居上。也就是說你可能是先start()了,但是不一定能先run()。

使用繼承thread的方式進行類比賣票

public class SoldTicketThread extends Thread {
    private int ticket = 5;
    private String name;

    // 構造方法
    public SoldTicketThread(String name) {

        this.name = name;

    }

    public void run() {
        while (ticket > 0) {
            System.out.println(name + "賣出了一張票,剩餘" + (--ticket) + "張票");
        }
    }

    public static void main(String[] args) {
        // 建立三個線程,類比三個視窗賣票
        SoldTicketThread wd1 = new SoldTicketThread("視窗一");
        SoldTicketThread wd2 = new SoldTicketThread("視窗二");
        SoldTicketThread wd3 = new SoldTicketThread("視窗三");
        // 啟動者三個線程,也就是視窗開始賣票
        wd1.start();
        wd2.start();
        wd3.start();
    }
}

運行結果:(這是因為我們建立了3個線程,每個線程都有5張票的資源,所以每個線程都賣自己的5張票,無法實現資源共用)

視窗二賣出了一張票,剩餘4張票
視窗一賣出了一張票,剩餘4張票
視窗一賣出了一張票,剩餘3張票
視窗一賣出了一張票,剩餘2張票
視窗一賣出了一張票,剩餘1張票
視窗一賣出了一張票,剩餘0張票
視窗二賣出了一張票,剩餘3張票
視窗二賣出了一張票,剩餘2張票
視窗二賣出了一張票,剩餘1張票
視窗二賣出了一張票,剩餘0張票
視窗三賣出了一張票,剩餘4張票
視窗三賣出了一張票,剩餘3張票
視窗三賣出了一張票,剩餘2張票
視窗三賣出了一張票,剩餘1張票
視窗三賣出了一張票,剩餘0張票

綜合上面的結果,我們只能建立一個線程,拿到這5張票的共用資源

public class SoldTicketThread implements Runnable {
    private int ticket = 5;

    public void run() {
        while (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + "賣出了一張票,剩餘" + (--ticket) + "張票");
        }
    }

    public static void main(String[] args) {
        // 建立一個實現了runnable介面的對象,拿到這5張票的資源
        SoldTicketThread window = new SoldTicketThread();
        //將這個資源類作為參數傳遞到3個線程中
        Thread wd1=new Thread(window,"視窗一");
        Thread wd2=new Thread(window,"視窗二");
        Thread wd3=new Thread(window,"視窗三");
        // 啟動者三個線程,也就是視窗開始賣票
        wd1.start();
        wd2.start();
        wd3.start();
    }
}

運行結果:

視窗一賣出了一張票,剩餘4張票
視窗一賣出了一張票,剩餘2張票
視窗一賣出了一張票,剩餘1張票
視窗二賣出了一張票,剩餘3張票
視窗一賣出了一張票,剩餘0張票

如果你非要用繼承thread的方式的話。。。

public class SoldTicketThread extends Thread {
    private int ticket = 5;

    public void run() {
        while (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + "賣出了一張票,剩餘"
                    + (--ticket) + "張票");
        }
    }

    public static void main(String[] args) {
        SoldTicketThread window = new SoldTicketThread();
        Thread wd1 = new Thread(window, "視窗二");
        Thread wd2 = new Thread(window, "視窗一");
        Thread wd3 = new Thread(window, "視窗三");
        wd1.start();
        wd2.start();
        wd3.start();
    }
}

運行結果:視窗隨機,賣票順序隨機

視窗二賣出了一張票,剩餘4張票
視窗二賣出了一張票,剩餘1張票
視窗二賣出了一張票,剩餘0張票
視窗三賣出了一張票,剩餘2張票
視窗一賣出了一張票,剩餘3張票

好想讓這個賣票有個順序腫麼破。。。,使用synchronized鎖住賣票操作的整個內容,使一次只賣一次票。給我們的資源加把鎖


採用實現Runnable介面實現:

public class SoldTicketThread implements Runnable {
private int ticket = 5;
private synchronized void sale() {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "賣出了一張票,剩餘"+ (--ticket) + "張票");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public void run() {
while (ticket > 0) {
sale();
// 這裡要確保進入賣票環節前就把資源鎖住
}
}

public static void main(String[] args) {
SoldTicketThread window = new SoldTicketThread();
Thread wd1 = new Thread(window, "視窗二");
Thread wd2 = new Thread(window, "視窗一");
Thread wd3 = new Thread(window, "視窗三");
wd1.start();
wd2.start();
wd3.start();
}
}

運行結果:(線程間(視窗)會進行搶佔cpu資源,是隨機的)

視窗三賣出了一張票,剩餘4張票
視窗一賣出了一張票,剩餘3張票
視窗二賣出了一張票,剩餘2張票
視窗一賣出了一張票,剩餘1張票
視窗一賣出了一張票,剩餘0張票
繼承Thread類

public class SoldTicketThread extends Thread {
    private int ticket = 5;

    public synchronized  void sale() {
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + "賣出了一張票,剩餘"
                    + (--ticket) + "張票");
        }
    }

    public void run() {
        while (ticket > 0) {
            sale();
        }
    }

    public static void main(String[] args) {
        SoldTicketThread window = new SoldTicketThread();
        Thread wd1 = new Thread(window, "視窗二");
        Thread wd2 = new Thread(window, "視窗一");
        Thread wd3 = new Thread(window, "視窗三");
        wd1.start();
        wd2.start();
        wd3.start();
    }
}

運行結果:(視窗會進行搶佔cpu資源,是隨機的)

視窗三賣出了一張票,剩餘4張票
視窗一賣出了一張票,剩餘3張票
視窗一賣出了一張票,剩餘2張票
視窗一賣出了一張票,剩餘1張票
視窗一賣出了一張票,剩餘0張票

總結:因為我們只是建立了一個擁有5張票的線程類的對象(有5張火車票),然後把這個對象作為參數傳遞給3個新建立的thread對象,所以共用了這5張火車票。然後我們再賣票操作加了synchronized操作,就可以實現按順序賣票了。

需要記住的點是,我覺得初學者老師會覺得程式是從上到下執行的,很符合我們的邏輯,但是線程可以看做是並行作業,並不是說你先start了,你就會先run。 


還要記錄的點事守護線程的點。。。在Dos環境下,jstack可以查看當前運行java類的pid,然後輸入 jstack -l pid可以查看到目前有什麼守護線程。。。。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.