1. 程式人生 > >建立多執行緒的4種方式

建立多執行緒的4種方式

1.執行緒是什麼?

        執行緒被稱為輕量級程序,是程式執行的最小單位,它是指在程式執行過程中,能夠執行程式碼的一個執行單位。每個程式程式都至少有一個執行緒,也即是程式本身

2.執行緒狀態

        Java語言定義了5種執行緒狀態,在任意一個時間點,一個執行緒只能有且只有其中一個狀態。,這5種狀態如下:

(1)新建(New):建立後尚未啟動的執行緒處於這種狀態

(2)執行(Runable):Runable包括了作業系統執行緒狀態的Running和Ready,也就是處於此狀態的執行緒有可能正在執行,也有可能正在等待著CPU為它分配執行時間。

(3)等待(Wating):處於這種狀態的執行緒不會被分配CPU執行時間。等待狀態又分為無限期等待和有限期等待,處於無限期等待的執行緒需要被其他執行緒顯示地喚醒,沒有設定Timeout引數的Object.wait()、沒有設定Timeout引數的Thread.join()方法都會使執行緒進入無限期等待狀態;有限期等待狀態無須等待被其他執行緒顯示地喚醒,在一定時間之後它們會由系統自動喚醒,Thread.sleep()、設定了Timeout引數的Object.wait()、設定了Timeout引數的Thread.join()方法都會使執行緒進入有限期等待狀態。

(4)阻塞(Blocked):執行緒被阻塞了,“阻塞狀態”與”等待狀態“的區別是:”阻塞狀態“在等待著獲取到一個排他鎖,這個時間將在另外一個執行緒放棄這個鎖的時候發生;而”等待狀態“則是在等待一段時間或者喚醒動作的發生。在程式等待進入同步區域的時候,執行緒將進入這種狀態。

(5)結束(Terminated):已終止執行緒的執行緒狀態,執行緒已經結束執行。

下圖是5種狀態轉換圖:

 

                

3.執行緒同步方法

        執行緒有4中同步方法,分別為wait()、sleep()、notify()和notifyAll()。

wait():使執行緒處於一種等待狀態,釋放所持有的物件鎖。

sleep():使一個正在執行的執行緒處於睡眠狀態,是一個靜態方法,呼叫它時要捕獲InterruptedException異常,不釋放物件鎖。

notify():喚醒一個正在等待狀態的執行緒。注意呼叫此方法時,並不能確切知道喚醒的是哪一個等待狀態的執行緒,是由JVM來決定喚醒哪個執行緒,不是由執行緒優先順序決定的。

notifyAll():喚醒所有等待狀態的執行緒,注意並不是給所有喚醒執行緒一個物件鎖,而是讓它們競爭。

4.建立執行緒的方式

        在JDK1.5之前,建立執行緒就只有兩種方式,即繼承java.lang.Thread類和實現java.lang.Runnable介面;而在JDK1.5以後,增加了兩個建立執行緒的方式,即實現java.util.concurrent.Callable介面和執行緒池。下面是這4種方式建立執行緒的程式碼實現。

4.1繼承Thread類

 

//繼承Thread類來建立執行緒
public class ThreadTest {
 
    public static void main(String[] args) {
        //設定執行緒名字
        Thread.currentThread().setName("main thread");
        MyThread myThread = new MyThread();
        myThread.setName("子執行緒:");
        //開啟執行緒
        myThread.start();
        for(int i = 0;i<5;i++){
            System.out.println(Thread.currentThread().getName() + i);
        }
    }
}
 
class MyThread extends Thread{
    //重寫run()方法
    public void run(){
        for(int i = 0;i < 10; i++){
            System.out.println(Thread.currentThread().getName() + i);
        }
    }
}

 

4.2實現Runnable介面

//實現Runnable介面
public class RunnableTest {
 
	public static void main(String[] args) {
		//設定執行緒名字
		Thread.currentThread().setName("main thread:");
		Thread thread = new Thread(new MyRunnable());
		thread.setName("子執行緒:");
		//開啟執行緒
		thread.start();
		for(int i = 0; i <5;i++){
			System.out.println(Thread.currentThread().getName() + i);
		}
	}
}
 
class MyRunnable implements Runnable {
 
	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName() + i);
		}
	}
}

4.3實現Callable介面

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
//實現Callable介面
public class CallableTest {
 
    public static void main(String[] args) {
        //執行Callable 方式,需要FutureTask 實現實現,用於接收運算結果
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyCallable());
        new Thread(futureTask).start();
        //接收執行緒運算後的結果
        try {
            Integer sum = futureTask.get();
            System.out.println(sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
 
class MyCallable implements Callable<Integer> {
 
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 0; i < 100; i++) {
            sum += i;
        }
        return sum;
    }
}
        

 相較於實現Runnable 介面的實現,方法可以有返回值,並且丟擲異常。

4.4執行緒池

        執行緒池提供了一個執行緒佇列,佇列中儲存著所有等待狀態的執行緒。避免了建立與銷燬額外開銷,提交了響應速度。

 

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//執行緒池實現
public class ThreadPoolExecutorTest {
 
    public static void main(String[] args) {
        //建立執行緒池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        ThreadPool threadPool = new ThreadPool();
        for(int i =0;i<5;i++){
            //為執行緒池分配任務
            executorService.submit(threadPool);
        }
        //關閉執行緒池
        executorService.shutdown();
    }
}
 
class ThreadPool implements Runnable {
 
    @Override
    public void run() {
        for(int i = 0 ;i<10;i++){
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }

}