1. 程式人生 > >java向多執行緒中傳遞引數的三種方法詳細介紹

java向多執行緒中傳遞引數的三種方法詳細介紹

在傳統的同步開發模式下,當我們呼叫一個函式時,通過這個函式的引數將資料傳入,並通過這個函式的返回值來返回最終的計算結果。但在多執行緒的非同步開發模式下,資料的傳遞和返回和同步開發模式有很大的區別。由於執行緒的執行和結束是不可預料的,因此,在傳遞和返回資料時就無法象函式一樣通過函式引數和return語句來返回資料。本文就以上原因介紹了幾種用於向執行緒傳遞資料的方法,在下一篇文章中將介紹從執行緒中返回資料的方法。

欲先取之,必先予之。一般在使用執行緒時都需要有一些初始化資料,然後執行緒利用這些資料進行加工處理,並返回結果。在這個過程中最先要做的就是向執行緒中傳遞資料。

一、通過構造方法傳遞資料 在建立執行緒時,必須要建立一個Thread類的或其子類的例項。因此,我們不難想到在呼叫start方法之前通過執行緒類的構造方法將資料傳入執行緒。並將傳入的資料使用類變數儲存起來,以便執行緒使用(其實就是在run方法中使用)。下面的程式碼演示瞭如何通過構造方法來傳遞資料:

程式碼如下:

public class MyThread1 extends Thread
{
    private String name;
    public MyThread1(String name)
    {
        this.name = name;
    }
    public void run()
    {
        System.out.println("hello " + name);
    }
}

 使用該執行緒:

public static void main(String[] args)
{
    Thread thread = new MyThread1("world");
    thread.start();
}

執行結果:

由於這種方法是在建立執行緒物件的同時傳遞資料的,因此,線上程執行之前這些資料就就已經到位了,這樣就不會造成資料線上程執行後才傳入的現象。如果要傳遞更復雜的資料,可以使用集合、類等資料結構。使用構造方法來傳遞資料雖然比較安全,但如果要傳遞的資料比較多時,就會造成很多不便。由於Java沒有預設引數,要想實現類似預設引數的效果,就得使用過載,這樣不但使構造方法本身過於複雜,又會使構造方法在數量上大增。因此,要想避免這種情況,就得通過類方法或類變數來傳遞資料。

二、通過變數和方法傳遞資料 向物件中傳入資料一般有兩次機會,第一次機會是在建立物件時通過構造方法將資料傳入,另外一次機會就是在類中定義一系列的public的方法或變數(也可稱之為欄位)。然後在建立完物件後,通過物件例項逐個賦值。下面的程式碼是對MyThread1類的改版,使用了一個setName方法來設定 name變數:

程式碼如下:

package mythread;
public class MyThread2 implements Runnable
{
	private String name;
	public void setName(String name)
	{
		this.name = name;
	}
	public void run()
	{
		System.out.println("hello " + name);
	}
}

使用該執行緒:

public static void main(String[] args)
{
	MyThread2 myThread = new MyThread2();
	myThread.setName("world");
	Thread thread = new Thread(myThread);
	thread.start();
}

三、通過回撥函式傳遞資料 上面討論的兩種向執行緒中傳遞資料的方法是最常用的。但這兩種方法都是main方法中主動將資料傳入執行緒類的。這對於執行緒來說,是被動接收這些資料的。然而,在有些應用中需要線上程執行的過程中動態地獲取資料,如在下面程式碼的run方法中產生了3個隨機數,然後通過Work類的process方法求這三個隨機數的和,並通過Data類的value將結果返回。從這個例子可以看出,在返回value之前,必須要得到三個隨機數。也就是說,這個 value是無法事先就傳入執行緒類的。

程式碼如下:

package mythread;
class Data
{
	public int value = 0;
}
class Work
{
	public void process(Data data, Integer numbers)
	{
	for (int n : numbers)
		{
			data.value += n;
		}
	}
}
public class MyThread3 extends Thread
{
	private Work work;
	public MyThread3(Work work)
	{
		this.work = work;
	}
	public void run()
	{
		java.util.Random random = new java.util.Random();
		Data data = new Data();
		int n1 = random.nextInt(1000);
		int n2 = random.nextInt(2000);
		int n3 = random.nextInt(3000);
		work.process(data, n1, n2, n3); // 使用回撥函式
		System.out.println(String.valueOf(n1) + "+" + String.valueOf(n2) + "+"	+ String.valueOf(n3) + "=" + data.value);
	}
}

啟用執行緒:

public static void main(String[] args)
{
	Thread thread = new MyThread3(new Work());
	thread.start();
}

在上面程式碼中的process方法被稱為回撥函式。從本質上說,回撥函式就是事件函式。在Windows API中常使用回撥函式和呼叫API的程式之間進行資料互動。因此,呼叫回撥函式的過程就是最原始的引發事件的過程。在這個例子中呼叫了process方法來獲得資料也就相當於在run方法中引發了一個事件。