JAvaマルチスレッドレビュー1:スレッドの概念と作成

20757 ワード

1、プロセスとスレッドの概念 
現在、ほとんどのオペレーティングシステムでマルチタスクがサポートされています.通常、1つのタスクはプログラムであり、1つの実行中のプログラムはプロセスです.1つのプログラム行の場合、その内部で複数のタスクが実行されることもあります.プロセス内の各タスクの実行フローは、スレッドです.
したがって、スレッドは軽量レベルのプロセスとも呼ばれます.
要するに、スレッドはプロセスの構成部分であり、独立して、同時にタスクを実行することができます.
2、スレッドの作成と起動
Javaには、スレッドの作成と起動の2つの方法があります.
2.1 Threadクラスの作成と開始スレッドの継承
Threadクラスを継承してマルチスレッドを作成して起動するには、次の手順に従います.
1.Threadのサブクラスを作成し、runメソッドを書き換える.runメソッドではスレッドが実行するタスクであるため,runメソッドをスレッド実行体とも呼ぶ.
2.サブクラスのインスタンス、すなわちスレッドオブジェクトを作成します.
3、スレッドオブジェクトのstartメソッドを使用してスレッドを起動します.
スレッドクラスコードは次のとおりです.
 1 //    Thread       
 2 
 3 public class ThreadOne extends Thread{
 4 
 5     private int i;
 6 
 7    
 8 
 9     //  run  ,             
10 
11     @Override
12 
13     public void run() {
14 
15        for (i = 0; i < 20; i++) {
16 
17            //  Thread  ,      getName()            
18 
19            //         ,    this  
20 
21            System.out.println(getName()+" "+i);
22 
23        }
24 
25     }
26 
27 }

 
テストコードは次のとおりです.
 1 public class TestThreadOne {
 2 
 3     public static void main(String[] args) {
 4 
 5        for (int i = 0; i < 10; i++) {
 6 
 7            //         
 8 
 9            System.out.println(Thread.currentThread().getName()+" "+i);
10 
11            if (i==3) {
12 
13               //          
14 
15               new ThreadOne().start();
16 
17               //          
18 
19               new ThreadOne().start();
20 
21            }
22 
23        }
24 
25     }
26 
27 }

 
結果の一部は次のとおりです.
main 0
main 1
main 2
main 3
Thread-0 0
Thread-1 0
main 4
Thread-1 1
Thread-0 1
Thread-1 2
main 5

 
上記の実行結果から、テストクラスは明示的に2つのスレッドしか作成されていませんが、実際には3つのスレッドが実行されています.すなわち、メインスレッド、スレッド0、スレッド1です.ここで,メインスレッドのスレッド体はmainメソッドの内容である.
さらに、Thread-0とThread-1の2つのスレッドから出力される変数iの値は、ローカル変数ではなくインスタンスメンバー変数として不連続であることから、スレッドを作成するたびにThreadOneオブジェクトが作成されることがわかる.
2.2 Runnableインタフェース作成スレッドの実装
Runnableインタフェースでスレッドを作成して起動するには、次の手順に従います.
1.Runnableインタフェースの実装クラスを作成し、runメソッドを書き換える.runメソッドの内容は、スレッドが実行するタスクです.
2.Runnable実装クラスのインスタンスを作成し、そのインスタンスをThreadのtargetとしてThreadオブジェクトを作成する.このThreadオブジェクトこそ本当のスレッドクラスです.
 
スレッドクラスコードは次のとおりです.
 1 //    Runnable       
 2 
 3 public class ThreadTwo implements Runnable{
 4 
 5     private int i;
 6 
 7    
 8 
 9     //run           
10 
11     @Override
12 
13     public void run() {
14 
15        for (i = 0; i < 5; i++) {
16 
17            //  Runnable        ,    Thread.currentThread()       
18 
19            System.out.println(Thread.currentThread().getName()+" "+i);
20 
21        }
22 
23     }
24 
25 }

 
テストコードは次のとおりです.
 1 public class TestThreadTwo {
 2 
 3     public static void main(String[] args) {
 4 
 5        for (int i = 0; i < 5; i++) {
 6 
 7            //         
 8 
 9            System.out.println(Thread.currentThread().getName()+" "+i);
10 
11            if (i==3) {
12 
13               ThreadTwo threadTwo = new ThreadTwo();
14 
15               //          
16 
17               new Thread(threadTwo).start();
18 
19               //          
20 
21               new Thread(threadTwo).start();
22 
23            }
24 
25        }
26 
27     }
28 
29 }

 
実行結果は次のとおりです.
 1 main 0
 2 
 3 main 1
 4 
 5 main 2
 6 
 7 main 3
 8 
 9 Thread-0 0
10 
11 Thread-1 0
12 
13 main 4
14 
15 Thread-1 2
16 
17 Thread-0 1
18 
19 Thread-0 4
20 
21 Thread-1 3

 
実行結果から、Thread-0とThread-1で印刷されたi値は連続しており、この2つのスレッドが1つのインスタンスを共有していることを示しています.これは、作成した2つのThreadクラスが同じRunnableオブジェクトをtargetとして使用するためです.
実際の開発では,Runnableインタフェースを実装する方法を用いてスレッドを作成することを推奨し,実装または継承も可能である.
2.3戻り値のあるスレッド
JDK 1.5からjavaはCallableインタフェースとFutureインタフェースを提供し、スレッドの戻り値を取得します.
CallableはRunnableの強化版に似ており,スレッドの実行体としてcall()メソッドを提供する.Runnableのrun()メソッドよりもcall()メソッドの方が強力です.
  • call()メソッドには、戻り値
  • がある.
  • call()は、例外
  • を放出することを宣言することができる.
    ただし、CallableオブジェクトはThreadのtargetとして直接使用することはできません.Futureオブジェクトで包装しなければなりません.具体的な使用手順は次のとおりです.
  • Callableの実装クラスを作成し、callメソッドを実装します.汎用的な制限があることに注意してください.
  • FutureTaskを使用してCallableオブジェクトをパッケージします.
  • FutureTaskをtargetとしてThreadに転送し、起動スレッドを作成します.
  • FutureTaskオブジェクトを呼び出すメソッドは、戻り値を取得します.

  • スレッドコード:
     1 public class CallableOne implements Callable{
     2 
     3     @Override
     4 
     5     public Integer call() throws Exception {
     6 
     7        int i = 0;
     8 
     9        for(i=0;i<10;i++){
    10 
    11            System.out.println(Thread.currentThread().getName()+" "+i);
    12 
    13        }
    14 
    15        //     ,          
    16 
    17        Thread.sleep(5000);
    18 
    19        return i;
    20 
    21     }
    22 
    23 }

     
    テストコード:
     1 public class TestCallable {
     2 
     3     public static void main(String[] args) {
     4 
     5        //  Callable  
     6 
     7        CallableOne callableOne = new CallableOne();
     8 
     9        //  FutureTask  Callable  
    10 
    11        FutureTask futureTask = new FutureTask(callableOne);
    12 
    13        for(int i=0;i<100;i++){
    14 
    15            System.out.println(Thread.currentThread().getName()+" "+i);
    16 
    17            //i  3      ,               
    18 
    19            if (i==3) {
    20 
    21               //FutureTask Runnable   ,   Thread  target
    22 
    23               new Thread(futureTask).start();
    24 
    25            }
    26 
    27            //i  80             ,        ,       
    28 
    29            if (i==80) {
    30 
    31               try {
    32 
    33                   System.out.println("      :"+futureTask.get());
    34 
    35               } catch (Exception e) {
    36 
    37                   e.printStackTrace();
    38 
    39               }
    40 
    41            }
    42 
    43        }
    44 
    45     }
    46 
    47 }

     
    以上のコードでは、iが3に等しいときにサブスレッドが起動し、メインスレッドとサブスレッドが交互に実行されることがわかります.iが80に等しいときにサブスレッドの戻り値を取得すると、結果が戻るまでメインスレッドがブロックされます.