1. 程式人生 > 實用技巧 >多執行緒和執行緒池

多執行緒和執行緒池

1.1多執行緒介紹

程序:程序指正在執行的程式。確切的來說,當一個程式進入記憶體執行,即變成一個程序,程序是處於執行過程中的程式,並且具有一定獨立功能

執行緒:執行緒是程序中的一個執行單元,負責當前程序中程式的執行,一個程序中至少有一個執行緒。一個程序中是可以有多個執行緒的,這個應用程式也可以稱之為多執行緒程式。

l單執行緒程式:即,若有多個任務只能依次執行。當上一個任務執行結束後,下一個任務開始執行。如,去網咖上網,網咖只能讓一個人上網,當這個人下機後,下一個人才能上網。

l多執行緒程式:即,若有多個任務可以同時執行。如,去網咖上網,網咖能夠讓多個人同時上網。

1.2Thread

Thread是程式中的執行執行緒。Java 虛擬機器允許應用程式併發地執行多個執行執行緒。

建立新執行執行緒有兩種方法。

l一種方法是將類宣告為 Thread 的子類。該子類應重寫 Thread 類的 run 方法。建立物件,開啟執行緒。run方法相當於其他執行緒的main方法。

l另一種方法是宣告一個實現 Runnable 介面的類。該類然後實現 run 方法。然後建立Runnable的子類物件,傳入到某個執行緒的構造方法中,開啟執行緒。

1.3建立執行緒方式一繼承Thread

1 定義一個類繼承Thread。

2 重寫run方法。

3 建立子類物件,就是建立執行緒物件。

4 呼叫start方法,開啟執行緒並讓執行緒執行,同時還會告訴jvm去呼叫run方法。

主程式程式碼

public class Demo01 {
    public static void main(String[] args) {
        //建立自定義執行緒物件
        MyThread mt = new MyThread("新的執行緒!");
        //開啟新執行緒
        mt.start();
        //在主方法中執行for迴圈
        for (int i = 0; i < 10; i++) {
            System.out.println(
"main執行緒!"+i); } } }

多執行緒程式程式碼

public class MyThread extends Thread {
    //定義指定執行緒名稱的構造方法
    public MyThread(String name) {
        //呼叫父類的String引數的構造方法,指定執行緒的名稱
        super(name);
    }
    /**
     * 重寫run方法,完成該執行緒執行的邏輯
     */
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(getName()+":正在執行!"+i);
        }
    }
}

獲取執行緒名稱

lThread.currentThread()獲取當前執行緒物件

lThread.currentThread().getName();獲取當前執行緒物件的名稱

1.4建立執行緒方式實現Runnable介面

建立執行緒的另一種方法是宣告實現 Runnable 介面的類。該類然後實現 run 方法。然後建立Runnable的子類物件,傳入到某個執行緒的構造方法中開啟執行緒.

介面中的方法

lThread類構造方法

1、定義類實現Runnable介面。

2、覆蓋介面中的run方法。。

3、建立Thread類的物件

4、將Runnable介面的子類物件作為引數傳遞給Thread類的建構函式。

5、呼叫Thread類的start方法開啟執行緒。

演示程式碼

public class Demo02 {
    public static void main(String[] args) {
        //建立執行緒執行目標類物件
        Runnable runn = new MyRunnable();
        //將Runnable介面的子類物件作為引數傳遞給Thread類的建構函式
        Thread thread = new Thread(runn);
        Thread thread2 = new Thread(runn);
        //開啟執行緒
        thread.start();
        thread2.start();
        for (int i = 0; i < 10; i++) {
            System.out.println("main執行緒:正在執行!"+i);
        }
    }
}

l自定義執行緒執行任務

public class MyRunnable implements Runnable{

    //定義執行緒要執行的run方法邏輯
    @Override
    public void run() {
        
        for (int i = 0; i < 10; i++) {
            System.out.println("我的執行緒:正在執行!"+i);
        }
    }
}

2.1執行緒池概念

執行緒池,其實就是一個容納多個執行緒的容器,其中的執行緒可以反覆使用,省去了頻繁建立執行緒物件的操作,無需反覆建立執行緒而消耗過多資源.

使用執行緒池方式--Runnable介面

通常,執行緒池都是通過執行緒池工廠建立,再呼叫執行緒池中的方法獲取執行緒,再通過執行緒去執行任務方法。

lExecutors:執行緒池建立工廠類

npublic static ExecutorService newFixedThreadPool(int nThreads):返回執行緒池物件

lExecutorService:執行緒池類

nFuture<?> submit(Runnabletask):獲取執行緒池中的某一個執行緒物件,並執行

lFuture介面:用來記錄執行緒任務執行完畢後產生的結果。執行緒池建立與使用

l使用執行緒池中執行緒物件的步驟:

n建立執行緒池物件

n建立Runnable介面子類物件

n提交Runnable介面子類物件

n關閉執行緒池

程式碼演示

public class ThreadPoolDemo {
    public static void main(String[] args) {
        //建立執行緒池物件
        ExecutorService service = Executors.newFixedThreadPool(2);//包含2個執行緒物件
        //建立Runnable例項物件
        MyRunnable r = new MyRunnable();
        
        //自己建立執行緒物件的方式
        //Thread t = new Thread(r);
        //t.start(); ---> 呼叫MyRunnable中的run()
        
        //從執行緒池中獲取執行緒物件,然後呼叫MyRunnable中的run()
        service.submit(r);
        //再獲取個執行緒物件,呼叫MyRunnable中的run()
        service.submit(r);
        service.submit(r);
//注意:submit方法呼叫結束後,程式並不終止,是因為執行緒池控制了執行緒的關閉。將使用完的執行緒又歸還到了執行緒池中

//關閉執行緒池
        //service.shutdown();
    }
}

lRunnable介面實現類

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("我要一個教練");
        
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("教練來了: " +Thread.currentThread().getName());
        System.out.println("教我游泳,交完後,教練回到了游泳池");
    }
}

使用執行緒池方式Callable介面

lCallable介面:與Runnable介面功能相似,用來指定執行緒的任務。其中的call()方法,用來返回執行緒任務執行完畢後的結果,call方法可丟擲異常。

lExecutorService:執行緒池類

n<T> Future<T> submit(Callable<T>task):獲取執行緒池中的某一個執行緒物件,並執行執行緒中的call()方法

lFuture介面:用來記錄執行緒任務執行完畢後產生的結果。執行緒池建立與使用

l使用執行緒池中執行緒物件的步驟:

n建立執行緒池物件

n建立Callable介面子類物件

n提交Callable介面子類物件

n關閉執行緒池

程式碼演示

public class ThreadPoolDemo {
    public static void main(String[] args) {
        //建立執行緒池物件
        ExecutorService service = Executors.newFixedThreadPool(2);//包含2個執行緒物件
        //建立Callable物件
        MyCallable c = new MyCallable();
        
        //從執行緒池中獲取執行緒物件,然後呼叫MyRunnable中的run()
        service.submit(c);
        
        //再獲取個教練
        service.submit(c);
        service.submit(c);
//注意:submit方法呼叫結束後,程式並不終止,是因為執行緒池控制了執行緒的關閉。將使用完的執行緒又歸還到了執行緒池中

//關閉執行緒池
        //service.shutdown();
    }
}

lCallable介面實現類,call方法可丟擲異常、返回執行緒任務執行完畢後的結果

public class MyCallable implements Callable {
    @Override
    public Object call() throws Exception {
        System.out.println("我要一個教練:call");
        Thread.sleep(2000);
        System.out.println("教練來了: " +Thread.currentThread().getName());
        System.out.println("教我游泳,交完後,教練回到了游泳池");
        return null;
    }
}

l測試類

public class Demo01 {

public static void main(String[] args) {

//建立自定義執行緒物件

MyThread mt = new MyThread("新的執行緒!");

//開啟新執行緒

mt.start();

//在主方法中執行for迴圈

for (int i = 0; i < 10; i++) {

System.out.println("main執行緒!"+i);

}

}

}

l自定義執行緒類

public class MyThread extends Thread {

//定義指定執行緒名稱的構造方法

public MyThread(String name) {

//呼叫父類的String引數的構造方法,指定執行緒的名稱

super(name);

}

/**

* 重寫run方法,完成該執行緒執行的邏輯

*/

@Override

public void run() {

for (int i = 0; i < 10; i++) {

System.out.println(getName()+":正在執行!"+i);

}

}

}