1. 程式人生 > >java多執行緒-初探(一)

java多執行緒-初探(一)

啥是多執行緒?跟程序又是啥關係?

 

比方說:我去洗手,洗完手去吃飯。

程序(Processor)

洗手跟吃飯是兩個程序。

執行緒(Thread)

在洗手的程序裡,我同時聽歌,還唱歌。那這裡洗手是一個程序,聽歌跟唱歌是兩個執行緒。

在吃飯的程序裡,我同時聽歌,還唱歌。那這裡吃飯是一個程序,聽歌跟唱歌是兩個執行緒。

吃飯跟洗手兩個程序之間的執行緒互不干擾,同個程序之間的執行緒存在鎖、等待、喚醒等等等機制。

多執行緒:同一個程序內做多件事,每件事是一個執行緒

 

這裡建立一個普通java專案。

 

單執行緒示例

以吃飯為例,只有聽完歌才能唱歌,無法邊聽邊唱。

 

class Main

public class Main {

    /**
     * 吃飯
     * @param args
     */
    public static void main(String[] args) {
        Song song = new Song();
        while (!song.listenIsZero())
            song.doThing("listen") ;
        while (!song.singIsZero())
            song.doThing("sing") ;
        System.out.println("執行完成!");
    }
}

class Song

public class Song {

    // 待唱的歌曲數量
    private int singNum = 5 ;

    // 待聽的歌曲數量
    private int listenNum = 5 ;

    public boolean singIsZero(){
        return singNum == 0 ;
    }

    public boolean listenIsZero(){
        return listenNum == 0 ;
    }

    public void doThing(String thing){
        switch (thing){
            case "sing" : doSing(); break;
            case "listen" : doListen(); break;
        }
    }

    public void doSing(){
        try {
            // 唱歌需要時間,加時間能體現多執行緒的效果
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("唱了一首歌,剩餘:" + singNum-- +"首未唱");
        if (singIsZero()) System.out.println("唱完了!");
    }

    public void doListen(){
        try {
            // 聽歌需要時間,加時間能體現多執行緒的效果
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("聽了一首歌,剩餘:" + listenNum-- +"首未聽");
        if (listenIsZero()) System.out.println("聽完了!");
    }

}

執行結果

 

多執行緒示例(繼承Thread類)

可以在吃飯的程序裡,邊聽歌邊唱歌。同時進行。

建立一個類負責聽歌或者唱歌,繼承Thread,重寫run函式。

建立兩個執行緒,都start之後可以觀察到兩個執行緒同時呼叫doThing函式。

 

class Main

public class Main {

    /**
     * 吃飯
     * @param args
     */
    public static void main(String[] args) {
        // 單執行緒示例
        /*Song song = new Song();
        while (!song.listenIsZero())
            song.doThing("listen") ;
        while (!song.singIsZero())
            song.doThing("sing") ;*/

        // 多執行緒示例
        SongThread listen = new SongThread("listen", new Song());
        SongThread sing = new SongThread("sing", new Song());
        // 啟動兩個執行緒
        listen.start();
        sing.start();
        System.out.println("執行完成!");
    }
}

class SongThread

public class SongThread extends Thread{

    private Song song ;

    private String thing ;

    public SongThread(String thing, Song song){
        this.song = song;
        this.thing = thing;
    }

    public void run(){
        switch (thing){
            case "listen" : while (!song.listenIsZero()) song.doListen(); break;
            case "sing" : while (!song.singIsZero()) song.doSing(); break;
        }
    }

}

執行結果

 

多執行緒示例(實現Runnable介面)

建立一個類實現Runnable介面,然後new Thread的時候將實現類傳參之後start。

Thread與Runnable的關係:Thread類實現了Runnable介面。

 

class Main

public class Main {

    /**
     * 吃飯
     * @param args
     */
    public static void main(String[] args) {
        // 單執行緒示例
        /*Song song = new Song();
        while (!song.listenIsZero())
            song.doThing("listen") ;
        while (!song.singIsZero())
            song.doThing("sing") ;*/

        /*// 多執行緒示例 Thread
        SongThread listen = new SongThread("listen", new Song());
        SongThread sing = new SongThread("sing", new Song());
        // 啟動兩個執行緒
        listen.start();
        sing.start();
        System.out.println("執行完成!");*/

        // 多執行緒示例 實現Runnable介面
        SongRunnable listen = new SongRunnable("listen", new Song());
        SongRunnable sing = new SongRunnable("sing", new Song());
        // 啟動兩個執行緒
        new Thread(listen).start();
        new Thread(sing).start();
    }
}

 

class SongRunnable

public class SongRunnable implements Runnable{

    private Song song ;

    private String thing ;

    public SongRunnable(String thing, Song song){
        this.song = song;
        this.thing = thing;
    }

    public void run(){
        switch (thing){
            case "listen" : while (!song.listenIsZero()) song.doListen(); break;
            case "sing" : while (!song.singIsZero()) song.doSing(); break;
        }
    }

}

 

執行結果

 

java多執行緒-初探(二)

 

實際業務應用場景舉例

1.後臺需要定時給資料庫100w個使用者傳送提醒郵件。

 啟動兩個執行緒分別給50w個使用者發郵件。

2.不影響使用者情況下記錄使用者操作日誌(非同步)

 啟動一個執行緒去單獨執行記錄日誌的操作。