Javaにおけるマルチスレッド実装方式

5552 ワード

Javaにおけるマルチスレッド実装方式
私たちの開発の過程で、よくマルチスレッドの問題に遭遇します.マルチスレッドの実現方式には主に2つあります.Runnableインタフェースを実現し、Threadクラスを統合します.この2つのマルチスレッド実装の方法にもいくつかの違いがある.ネット上ではこの問題について、基本的に切符を買うシステムの例を使っています.次に、コードで次の切符を買うシステムをシミュレートし、2つの切符売り場で10枚の切符を発売し、1つの切符売り場で1つのスレッドを表すことを実現します.
シナリオ1
まず最も簡単な方法から、Thread類を2つ開いて切符を販売します.テストコードは次のとおりです.
public class ticketThread extends Thread {

    private int ticket = 10;
    
    public void run() {
        for(int i = 0; i < 10; i++){
            if(ticket > 0){
                try {
                    sleep(1000);
                    System.out.println(Thread.currentThread().getName() 
                            + "   ——>" + (ticket--) );                  
                } catch (Exception e) {
                    // TODO: handle exception
                    e.printStackTrace();
                }
            }
        }
    }
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new ticketThread().start();
        new ticketThread().start();
    }

}

テスト結果:Thread-0売票——>10 Thread-1売票——>10 Thread-1売票——>9 Thread-0売票——>9 Thread-1売票——>8 Thread-0売票——>8 Thread-1売票——>7 Thread-0売票——>7 Thread-0売票——>6 Thread-1売票——>6 Thread-0売票——>5 Thread-1売票——>5 Thread-1売票——>4 Thread-0売票——>->4 Thread-1売票——>3 Thread-0売票——>3 Thread-1売票——>2 Thread-0売票——>2 Thread-0売票——>1 Thread-1売票——>1結論:上記のテスト結果から、2つのスレッドはそれぞれ共通の10枚のチケットを売るのではなく、それぞれの10枚のチケットを売っていることがわかり、これは私たちの目標の複数のスレッドが同じリソースを処理することとは大きく異なる.2つのticketThreadオブジェクトを作成すると、2つのリソースが作成され、各リソースには10枚のチケットがあり、各リソースは独自にそれぞれのリソースを処理しています.したがって、この例では、このチケット販売システムでは、1つのリソースオブジェクトしか作成できませんが、同じリソースオブジェクトを処理するために複数のスレッドを作成し、各スレッドで同じプログラムコードを実行する必要があります.
シナリオ2
リソースオブジェクトを1つしか作成できない以上、ticketThreadを1つだけ作成し、2つの新しいスレッドを追加してチケット販売を実現します.
テストコード:
public class ticketThread extends Thread {

    private int ticket = 10;
    
    public void run() {
        for(int i = 0; i < 10; i++){
            synchronized(this){
                if(ticket > 0){
                    try {
                        sleep(1000);
                        System.out.println(Thread.currentThread().getName() 
                                + "   ——>" + (this.ticket--) );                 
                    } catch (Exception e) {
                        // TODO: handle exception
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ticketThread t1 = new ticketThread();
        new Thread(t1, "  1").start();
        new Thread(t1, "  2").start();
    }

}

テスト結果:スレッド1チケット販売——>10スレッド1チケット販売——>9スレッド2チケット販売——>8スレッド2チケット販売——>7スレッド2チケット販売——>6スレッド1チケット販売——>5スレッド1チケット販売——>4スレッド2チケット販売——>3スレッド2チケット販売——>2スレッド2チケット販売——>1
結論:この場合,同じリソースを複数のスレッドで処理することを実現した.ここでは,Thread(ThreadGroup groupOb, String threadName)を用いてticketThreadをパラメータとして新しく作成したスレッドに伝達する新しいスレッドを作成した.この場合、新しく作成された2つのスレッドは、ticketThreadrun()メソッドを実行し、2つのスレッドが同じリソースを処理することを実現する.しかし、原理的には、この案は案3と同じである.
シナリオ3Runnableを使用してマルチスレッドを実装する.テストコード:
public class ticketThread implements Runnable {

    private int ticket = 10;
    
    public void run() {
        for(int i = 0; i < 10; i++){
//          synchronized(this){
                if(ticket > 0){
                    try {
                        Thread.sleep(1000);
                        System.out.println(Thread.currentThread().getName() 
                                + "   ——>" + (ticket--) );   
                    } catch (Exception e) {
                        // TODO: handle exception
                        e.printStackTrace();
                    }
                }
            }
//      }
    }
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ticketThread t1 = new ticketThread();
        new Thread(t1, "  1").start();
        new Thread(t1, "  2").start();
    }

}



テスト結果:スレッド1チケット販売——>10スレッド2チケット販売——>9スレッド2チケット販売——>7スレッド1チケット販売——>8スレッド1チケット販売——>6スレッド2チケット販売——>5スレッド1チケット販売——>4スレッド2チケット販売——>3スレッド2チケット販売——>2スレッド1チケット販売——>1
結論:上記のテストコードでは、2つのスレッドを作成し、各県城は同じticketThreadオブジェクトのrun()メソッドを呼び出し、同じオブジェクトの変数(ticket)のインスタンスにアクセスし、このプログラムは私たちのニーズを完璧に満たしています.
RunnableとThreadの違いとつながり
  • クラスは親クラスを1つしか継承できません.これはThreadを使用する限界です.Runnableはインタフェースです.このインタフェースを実現すればいいです.従って、実際の開発プロセスでは、Runnableインタフェースによって実現され、Runnableはリソース共有の実現により適している.
  • は、Javaの単一継承特性がもたらす限界に比べてRunnableを使用することができ、Javaの単一継承特性がもたらす限界により、ある疲れたサブクラスを継承してマルチスレッドに入れる場合、1つのクラスが同時に2つの親クラスを持つことができないため、Threadクラスを継承する方法が使用できない場合、このクラスはRunnableインタフェースしか採用できない方法である.
  • は、実際にはThread Runnbaleインターフェースのサブクラスである.public class Thread extends Object implements Runnable
  • Runnableオブジェクトを使用する場合、Runnableで定義されたサブクラスにはstart()メソッドはなく、Threadクラスにのみ存在し、Threadクラスを観察すると、public Thread(Runnable target)のサブクラスインスタンスを受け入れる構造メソッドRunanbleがあり、つまりThreadクラスを起動してRunnableマルチスレッドを実現することができる.