JAVAマルチスレッド実現の4つの方法


一、方法一(Thread類の継承)
定義類はThreadを継承し、run方法を書き換えて、新しいスレッドのすることをrunメソッドに書いて、スレッドのオブジェクトを作成し、新しいスレッドを開いて、内部は自動的にrunメソッドを実行します。
public class Demo2 {
   public static void main(String[] args) {
      MyThread mt = new MyThread();     //4,  Thread      
      mt.start();                      //5,    
      
      for(int i = 0; i < 1000; i++) {
         System.out.println("bb");
      }
   }
}

class MyThread extends Thread {             //1,  Thread
   public void run() {                   //2,  run  
      for(int i = 0; i < 1000; i++) {       //3,         run   
         System.out.println("aaaaaaaaaaaa");
      }
   }
}
public static void main(String[] args) {
   new Thread() {                            //1,  Thread 
      public void run() {                         //2,  run  
         for(int i = 0; i < 1000; i++) {             //3,         run   
            System.out.println("aaaaaaaaaaaaaa");
         }
      }
   }.start();                               //4,    
}

二、方法二(Runnableインターフェースの実現)
定義類はRunnableインターフェースを実現し、run方法を実現し、新しいスレッドを行うことをrun方法に書いて、カスタマイズされたRunnableのサブオブジェクトを作成し、Threadオブジェクトを作成し、Runnableに伝え、start()を呼び出して新しいスレッドを開いて、内部で自動的にRunnableのrunを呼び出す()方法です。Thread(Runnable target)          新しいThreadオブジェクトを割り当てます。Thread(Runnable target, String name)          新しいThreadオブジェクトを割り当てます。
public class Demo3_Thread {
   public static void main(String[] args) {
      MyRunnable mr = new MyRunnable();  //4,  Runnable     
      //Runnable target = mr;    mr = 0x0011
      Thread t = new Thread(mr);       //5,         Thread     
      t.start();                   //6,    
      
      for(int i = 0; i < 1000; i++) {
         System.out.println("bb");
      }
   }
}

class MyRunnable implements Runnable {    //1,       Runnable
   @Override
   public void run() {                   //2,  run  
      for(int i = 0; i < 1000; i++) {       //3,         run   
         System.out.println("aaaaaaaaaaaa");
      }
   } 
}
public static void main(String[] args) {
   new Thread(new Runnable() {                //1, Runnable        Thread     
      public void run() {                         //2,  run  
         for(int i = 0; i < 1000; i++) {             //3,         run   
            System.out.println("bb");
         }
      }
   }).start();                                  //4,    
}
三、二種類の方式の違い
  • 継承Thread
  •        サブクラスでThread類のrun()を書き換えましたので、start()を呼び出したら、直接にサブタイプのrun()を探します。
           特典:Thread類で直接使用できる方法は、コードが簡単です。
           弊害:父ができたら、この方法は使えません。
  • Runnableインターフェース
  • を実現する。
           コンストラクタからRunnableの引用が入ってきました。メンバー変数はそれを覚えています。start()がrun()メソッドを呼び出した時、内部でメンバー変数Runnableの参照が空であるかどうかを判断します。空コンパイルでない場合はRunnableのrun()を見て、実行するのはサブクラスのrun()メソッドです。
           特典:自分で定義したスレッド類は親類があっても大丈夫です。親類があってもインターフェースが実現できます。インターフェースは多く実現できます。
           エラー:Threadを直接使うことができない方法は、スレッドオブジェクトを先に取得してから、Threadを得ることができます。コードが複雑です。
    四、方法三(Callableインターフェースを実現する)
    CallableインターフェースはRunnableと類似しており、その両方は他のスレッドによって実行される可能性のある他のクラスのために設計されている。しかし、Runnableは結果に戻りません。検査された異常を投げ出すことができません。
    public class Demo3_Thread {
       public static void main(String[] args) throws Exception{
          MyCallable mc = new MyCallable(100);
    
          FutureTask f = new FutureTask<>(mc);
          new Thread(f).start();
    
          System.out.println(f.get());
       }
    
    }
    
    class MyCallable implements Callable {
    
       private int number;
    
       public MyCallable(int number) {
          this.number = number;
       }
    
       @Override
       public Integer call() throws Exception {
          int sum = 0;
          for (int x = 1; x <= number; x++) {
             sum += x;
          }
          return sum;
       }
    }
    五、方法四(スレッド池)
    1.概要
    新しいスレッドを起動するプログラムのコストは、オペレーティングシステムとの相互作用を含むため、比較的高い。スレッドプールを使用すると、パフォーマンスを向上させることができます。特に、プログラム中に大量の生存期間が短いスレッドを作成する場合は、スレッドプールの使用を考慮しなければなりません。スレッドのプールの各スレッドコードが終了すると、死亡することはなく、再びスレッドのプールに戻って空き状態になり、次のオブジェクトが使用されるのを待つ。JDK 5の前に、私達は手動で自分のスレッド池を実現しなければならなくて、JDK 5から、Javaは支持スレッド池を内蔵します。
    2.Exectors工場類static ExecutorServicenewFixedThreadPool(int nThreads)          これらのスレッドは、固定スレッド数を再利用できるスレッドプールを作成し、共有する非境界キュー方式で実行します。static ExecutorServicenewSingleThreadExecutor()          このスレッドは、単一のウォーカースレッドを使用したExectorを作成し、非境界のキューで実行します。
    これらの方法の戻り値は、ExectorServiceオブジェクトであり、オブジェクトは、RunnableオブジェクトまたはCallableオブジェクトの代表的なスレッドを実行することができるスレッドを表している。これは次のような方法を提供しています。 Futuresubmit(Callable task)           を すタスクを するために し、タスクの の を すFutureを します。 Future>submit(Runnable task)          Runnableタスクを するために し、タスクを すFutureを します。
    Futureは の を します。 が するのを つ を し、 の を る。 Vget()           であれば、 が するのを って、その を します。
    3.
  • スレッドリングオブジェクト
  • を する。
  • Runnable
  • を する。
  • Runnable
  • スレッド を じる
  • 4.コード
    ①Runnableの
    ExecutorService pool = Executors.newFixedThreadPool(2);
    
    //     Runnable    Callable       
    pool.submit(new MyRunnable());
    pool.submit(new MyRunnable());
    
    //     
    pool.shutdown();
    ②Callableを する
    //        
    ExecutorService pool = Executors.newFixedThreadPool(2);
    
    //     Runnable    Callable       
    Future f1 = pool.submit(new MyCallable(100));
    Future f2 = pool.submit(new MyCallable(200));
    
    // V get()
    Integer i1 = f1.get();
    Integer i2 = f2.get();
    
    System.out.println(i1);
    System.out.println(i2);
    
    //   
    pool.shutdown();
    
    public class MyCallable implements Callable {
    	private int number;
    		
    	public MyCallable(int number) {
    		this.number = number;
    	}
    		
    	@Override
    	public Integer call() throws Exception {
    		int sum = 0;
    		for (int x = 1; x <= number; x++) {
    			sum += x;
    		}
    		return sum;
    	}		
    }
    :
  • は、 り
  • を してもよい。
  • を げることができます。
    :
  • コードは ですので、 は
  • を いません。