1. 程式人生 > >三種新增執行緒的方式及其區別

三種新增執行緒的方式及其區別

我們常見的新增執行緒的方法通常是兩種: ①繼承Thread類,實現run方法,呼叫start()方法開啟執行緒; ②實現Runnable介面,實現run方法, 呼叫start()方法開啟執行緒; 其實還有第三種常用的新增執行緒的方式: 是通過Callable和Future建立執行緒

1. 繼承Thread類新增執行緒

使用該方法新增執行緒的步驟是: 第一步:建立類繼承Thread類 第二步:實現run方法,將任務寫在run方法裡面 第三步:在main方法new出該類,呼叫start方法開啟執行緒

程式碼實現如下:


public class ThreadTest extends Thread {
	
	//實現run方法
	@Override
	public void run() {
		for(int i=0;i<=6;i++) {
		   System.out.println(Thread.currentThread().getName() + "--" + i);
		   try {
			Thread.sleep(new Random().nextInt(100));  //休眠
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		}
		System.out.println(Thread.currentThread().getName()+"--finsh");
	}
	
	
	public static void main(String[] args) {
		new ThreadTest("A").start();
		new ThreadTest("B").start();
	}
	
}

輸出結果為(結果不唯一):

Thread0–1 Thread1–1 Thread0–2 Thread0–3 Thread1–2 Thread1–3 Thread0–4 Thread0–5 Thread0–6 Thread0–finish Thread1–4 Thread1–5 Thread1–6 Thread1–finish

我們可以發現,繼承Thread類建立的執行緒可以擁有自己獨立的類成員變數i。

2.實現Runnable介面建立執行緒

使用該方法建立執行緒的步驟是: 第一步:建立類實現Runnable介面; 第二步:實現run方法,將任務寫在run方法內; 第三步:建立Thread物件,建立Runnable例項,將其傳入Thread物件中; 第四步:呼叫start方法開啟執行緒。

程式碼實現如下:

public class RunableTest implements Runnable{
	private int j;
	
	//實現run方法
	@Override
	public void run() {
		for(int i=0;i<=10;i++) {
			   try {
				Thread.sleep(new Random().nextInt(100)); //休眠
				j++;
				 System.out.println(Thread.currentThread().getName()+"--"+j);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			}
			System.out.println(name+" finsh");
	}
 	
  public static void main(String[] args) {
	  RunableTest R=new RunableTest();
	  new Thread(R).start();
	  new Thread(R).start();
	}
}

執行結果為:

Thread0–1 Thread1–2 Thread0–3 Thread0–4 Thread1–5 Thread1–6 Thread0–7 Thread0–8 Thread0–9 Thread0–10

在加入休眠操作之後,可以發現,雖然執行緒不同,但是i卻是程序共享的。

3.通過Callable和Future建立執行緒

先簡單瞭解以下Callable和Future介面以及他的實現類FutureTask:

  • Callable是一個介面,它與Runnable極其相似,但在Runnable介面中run方法是執行緒執行體,而在Callable中call方法是執行緒執行體。
  • call能夠實現run能實現的所有功能,除此之外還多出以下兩個功能:
    • call方法允許有返回值,可以在執行完後返回資料;
    • call方法能夠宣告丟擲的異常;
  • FutureTask類實現了Runnable和Future介面;
  • Future介面是對Callable任務的執行結果進行取消,查詢是否完成。

使用該方法建立執行緒的步驟是: 第一步:建立類實現Callable介面; 第二步:實現call方法, 將任務放在call方法內; 第三步:建立Callable例項,建立FutureTask例項,將Callable例項傳入FutureTask中; 第四步:建立Thread物件,將FutureTask例項傳入Thread物件中; 第五步:呼叫start方法, 開啟執行緒。

程式碼實現如下:


import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
 
public class CallableTest implements Callable<Integer> {

   //實現call方法
	@Override
	public Integer call() throws Exception {
		int i=0;
		for(;i<10;i++) {
			   System.out.println(Thread.currentThread().getName()+ "--" + i);
			   try {
				Thread.sleep(new Random().nextInt(100));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			}
			System.out.println("finsh");
		return i;
	}
 
public static void main(String[] args) {
	CallableTest callable1 = new CallableTest();
	CallableTest callable2 = new CallableTest();
	FutureTask<Integer> furureTask1 = new FutureTask<Integer>(callable1);
	FutureTask<Integer> futureTask2 = new FutureTask<Integer>(callable2);
	new Thread(Task1).start();
	new Thread(Task2).start();
	}
}

輸出結果如下:

Thread0–1 Thread1–1 Thread0–2 Thread0–3 Thread1–2 Thread0–4 Thread0–5 Thread0–6 finish Thread1–3 Thread1–4 Thread1–5 Thread1–6 finish

在該輸出方法中,執行緒在執行過程中並不會輸出返回值,如果要獲得返回值則呼叫futureTask1.get()即可得到返回值。

4.區別:

三者區別在以上已經有所說明,總結來說有以下三點:

  1. 繼承Thead類建立的執行緒可以擁有獨立的成員變數,而實現Runnable介面建立的執行緒中的成員變數則是程序共享的;
  2. 三者的建立方式有所不同;
  3. 使用Callable和Task建立的執行緒的執行體與前兩者的執行體不同,前兩者是run方法作為執行體,後者是call方法作為執行體。call方法作為執行體有以下兩個優勢:1)call方法允許有返回值,可以在執行完後返回資料; 2) call方法能夠宣告丟擲的異常。