Java多線程:向線程傳遞參數的三種方法


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

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

一、通過構造方法傳遞數據 

在創建線程時,必須要建立一個Thread類的或其子類的實例。因此,我們不難想到在調用start方法之前通過線程類的構造方法將數據傳入線程。並將傳入的數據使用類變量保存起來,以便線程使用(其實就是在run方法中使用)。下面的代碼演示了如何通過構造方法來傳遞數據:


   
   
  
  
          
  1. package mythread;
  2. public class MyThread1 extends Thread
  3. {
  4. private String name;
  5. public MyThread1(String name)
  6. {
  7. this.name = name;
  8. }
  9. public void run()
  10. {
  11. System.out.println( "hello " + name);
  12. }
  13. public static void main(String[] args)
  14. {
  15. Thread thread = new MyThread1( "world");
  16. thread.start();
  17. }
  18. }

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

二、通過變量和方法傳遞數據

    向對象中傳入數據一般有兩次機會,第一次機會是在建立對象時通過構造方法將數據傳入,另外一次機會就是在類中定義一系列的public的方法或變量(也可稱之為字段)。然后在建立完對象后,通過對象實例逐個賦值。下面的代碼是對MyThread1類的改版,使用了一個setName方法來設置name變量:


   
   
  
  
          
  1. package mythread;
  2. public class MyThread2 implements Runnable
  3. {
  4. private String name;
  5. public void setName(String name)
  6. {
  7. this.name = name;
  8. }
  9. public void run()
  10. {
  11. System.out.println( "hello " + name);
  12. }
  13. public static void main(String[] args)
  14. {
  15. MyThread2 myThread = new MyThread2();
  16. myThread.setName( "world");
  17. Thread thread = new Thread(myThread);
  18. thread.start();
  19. }
  20. }

三、通過回調函數傳遞數據

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


   
   
  
  
          
  1. package mythread;
  2. class Data
  3. {
  4. public int value = 0;
  5. }
  6. class Work
  7. {
  8. public void process(Data data, Integer numbers)
  9. {
  10. for ( int n : numbers)
  11. {
  12. data.value += n;
  13. }
  14. }
  15. }
  16. public class MyThread3 extends Thread
  17. {
  18. private Work work;
  19. public MyThread3(Work work)
  20. {
  21. this.work = work;
  22. }
  23. public void run()
  24. {
  25. java.util.Random random = new java.util.Random();
  26. Data data = new Data();
  27. int n1 = random.nextInt( 1000);
  28. int n2 = random.nextInt( 2000);
  29. int n3 = random.nextInt( 3000);
  30. work.process(data, n1, n2, n3); // 使用回調函數
  31. System.out.println(String.valueOf(n1) + "+" + String.valueOf(n2) + "+"
  32. + String.valueOf(n3) + "=" + data.value);
  33. }
  34. public static void main(String[] args)
  35. {
  36. Thread thread = new MyThread3( new Work());
  37. thread.start();
  38. }
  39. }

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



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM