JAVASE-マルチスレッド

7451 ワード

Thread


マルチスレッドは、プログラム内で複数のタスクを同時に実行する必要がある操作を解決し、実行する必要があるタスクを実行するためにスレッドを作成することができます.スレッドを作成する方法は2つあります.1:Threadクラスを継承するクラスを作成し、対応するアクションを実行するrunメソッドをクラスに書き換える
class MyThread extends Thread {
   public void run(){
     for(int i=0;i<1000;i++){
       system.out.println(11111);
    }
 }
}
// Thread
public static void main(String[] args){
  Thread t1 = new MyThread();
}
t1.start();

なお、スレッドを起動するには、書き換えrunメソッドではなくThreadのstartメソッドを呼び出す必要があります.runメソッドでは、このスレッドが具体的に行う必要があることを定義しています.startメソッドが呼び出されると、スレッドがスレッドスケジューリングに組み込まれ、スレッドスケジューリングはCPUタイムスライスを自動的に割り当ててスレッドを実行し、スレッドが実行されるとrunメソッドが自動的に呼び出されます.またrunメソッドはstartメソッドの呼び出しが完了した後に実行され、startメソッドの実行中に実行されるものではありません.この作成方法は匿名クラスで実現でき,比較的簡単である.
Thread t2 = new Thread(){
  public void run(){
    system.out.println(" ");
 }
}

このスレッド作成方式は,a,Javaは単一継承であるため,現在のクラスがThreadクラスを継承している場合,他の親クラスを継承して再利用を実現することはできず,Threadを継承しなければ単一スレッドとして同時実行することはできず,ここで継承競合が生じる.b、スレッドクラスは操作を実行するにはrun方法を書き直さなければならないため、スレッドと実行するタスクに強い結合関係が現れ、このスレッドはこのタスクしか実行できず、私たちの後続のこのスレッドの多重化に不利であり、私たちがどれだけのタスクがどれだけのスレッドを開くことができないかを知って、できるだけ効率を保証しながらスレッドの数を減らす.2:Runnableインタフェースを個別に作成し、runメソッドを書き換えてタスクを個別に定義し、ThreadインスタンスによってRunnableインタフェースを実現し、スレッドとタスクのデカップリングを実現する
Runnable r1 = new Runnable(){
  public void run(){
    system.out.println(" ");
  }
}
Runnable r2 = new Runnable(){
  public void run(){
    system.out.println(" ");
  }
}
Thread t = new Thread(r1);
Thread t1 = new Thread(r2);
t.start();
t1.start();

現在のスレッドJavaを取得するすべてのプログラムはスレッド上を走っており、Javaはこのスレッドstatic Thread currentThread()がどのメソッドでこのメソッドを実行するとそのメソッドを実行するスレッドを取得する静的メソッドを提供している.mainメソッドもスレッドによって実行され、プログラムが起動するとオペレーティングシステムが仮想マシンを実行するプロセスを作成し、プロセスが実行されると、mainメソッドを実行するためにスレッドが作成され、プロセスには少なくとも1つのスレッドが必要です.
Thread t = Thread.currentThread();
System.out.println(t);//Thread[main,5,main]

スレッド関連情報を取得するAPI
Thread main = Thread.currentThread();
// ID
long id = main.getId();
// 
String name = main.getName();
// 
int priority = main.getPriority();
// 
boolean isDaemon = main.isDaemon();
// 
boolean isAlive = main.isAlive();
// 
boolean isInterrupted = main.isInterrupted();

スレッド優先度スレッドはスレッドスケジューリングの作業に関与することができない.すなわち、スレッドはタイムスライスがどのスレッドに割り当てられるかを決定することができず、割り当ての具体的な回数を決定することもできないが、スレッド優先度を変更することでCPUタイムスライスに割り当てられる確率を高めることができ、スレッド優先度は10段階に分けられ、最低は1、デフォルト5、最高10であり、理論的に優先度が高いほどCPUタイムスライスを取得する確率が高くなる.
public static void main(String[] args) {
        new Thread(new Runnable(){
            
            @Override
            public void run() {
                for(int i = 0;i <10; i++){
                    Thread t = Thread.currentThread();
                    t.setPriority(Thread.MAX_PRIORITY);
                    System.out.println("max");
                }
            }
            
        }).start();
        new Thread(new Runnable(){

            @Override
            public void run() {
                for(int i = 0;i <10; i++){
                    Thread t = Thread.currentThread();
                    t.setPriority(Thread.NORM_PRIORITY);
                    System.out.println("normal");
                }
            }
            
        }).start();
        new Thread(new Runnable(){

            @Override
            public void run() {
                for(int i = 0;i <10; i++){
                    Thread t = Thread.currentThread();
                    t.setPriority(Thread.MAX_PRIORITY);
                    System.out.println("min");
                }
            }
            
        }).start();
    }

デーモンスレッドデーモンスレッドはバックグラウンドスレッドとも呼ばれ、1つのプロセスのすべてのフロントスレッドが終了すると、プロセスが終了する前にバックグラウンドスレッドを強制的に終了します.例えばJavaのGCは典型的なバックグラウンドスレッドであり、プログラムの実行中にGCはスタックにゴミがあるかどうかを定期的にチェックし、現在のステージスレッドが終了するとGCも停止します.
Thread t = new Thread(){
  public void run(){
     System.out.println(" ");
  }
};
// 
t.setDaemon(true);
t.start();

マルチスレッド同時セキュリティの問題


シンクロロック
1つのプログラムに多くのスレッドがある場合、複数のスレッドが同時に1つの方法にアクセスする現象が発生します.例えば、2人が同時にトイレに行きたい場合、衝突が発生します.プログラムの中でこの問題を解決する方法は現実と同じように、列に並ぶことです.列に並ぶ前提条件はトイレに鍵をかけることです.そうすれば、誰かが奪いたくても入れません.synchronizedキーワードを用いて必要なメソッドやコードブロックにロックをかけます.たとえば、1つのメソッドがロックされた後、複数のスレッドが同時に実行することは許可されません.このメソッドは同期メソッドと呼ばれています.
class Bathroom {
  public synchronized void goToBathroom(){
    // 5 
    Thread.sleep(5000);
    System.out.println(" ~");
  }
}
public static void main(String[] args){
  Bathroom bt = new Bathroom();
  Thread person1 = new Thread(){
    public void run(){
      bt.goToBathroom();
    }
  };
  Thread person2 = new Thread(){
    public void run(){
      bt.goToBathroom();
    }
  };
  person1.start();
  person2.start();
}

この2つのスレッドが実行されると、スレッドスケジューリングはランダムにタイムスライスを割り当てられ、1つのスレッドが5秒以内にメソッドにアクセスするとロックされ、他のスレッドはアクセスできず、アクセスが終了すると他のスレッドだけがアクセスできます.これで列に並ぶ効果があります.
同期ロックの範囲を効果的に縮小することで、安全を保証する前提の下で同時効率を高めることができます.例えば、デパートに行って服を買って、まず好きな服を選んでから試着室に持って行って服を試着することができます.この2つの過程で私たちは並ぶ必要はありません.試着したときだけ並んでドアを閉めて鍵をかけることができます.プログラムでは、
class Shopping{
  Thread t = Thread.currentThread();
  public void buy(){
     System.out.println(t+" ~");
     Thread.sleep(5000);

     synchronized(this){
     System.out.println(t+" ~ ~");
     Thread.sleep(5000);
  }
  System.out.println(t+" ~");
}

}
public class test{
  public static void main(String[] args){
    Shopping s = new Shopping();
    Thread person1 = new Thread(){
      public void run(){
        s.buy();
      }
    };
   Thread person2 = new Thread(){
      public void run(){
        s.buy();
      }
    };
    person1.start();
    person2.start();
  }
}

これにより、キュー時間を短縮し、デパートの稼働効率を向上させることができます.プログラムでは、多くのスレッドが同時に1つの方法にアクセスし、キューに並ばなければならない場合、同期範囲を縮小することができます.方法でキューに並ばなければならないコードブロックだけをロックし、方法の他のコードは同時に実行することができ、キュー時間を減らすことができます.ここで注意しなければならないのは、メソッド内のコードブロックをロックするときに同期モニタを指定することです.通常、thisで指定できます.すなわち、現在のオブジェクトです.コードブロックを同期するには、マルチスレッドで表示されるロックオブジェクトが同じオブジェクトであることを保証する必要があります.この例では、同じオブジェクトが同じデパートのインスタンスを指し、異なるデパート、すなわち異なるオブジェクトであれば、並んだり奪ったりする問題はありません.
静的メソッドの同期静的メソッドにロックをかけると、ロックオブジェクトは現在のクラスのクラスオブジェクトになります.JVMがクラスをロードすると、まずクラスのclassファイルを読み込み、同時にクラスのクラス情報を保存するクラスオブジェクトを作成します.クラスにはクラスオブジェクトがあり、1つしかないので、静的同期メソッドには同期効果があります.
反発ロック
反発ロックとは、最大1つのスレッドのみが持つことができるロックです.ロックされたオブジェクトが同じである場合、オブジェクトの下に2つのメソッドまたは2つのセグメントのコード以上にsynchronizedキーワードが追加されている場合、この2つのメソッドまたはコード反発を表します.反発は、1つのスレッドがロックを解除してコードを実行すると、別のロックされたコードの他のスレッドがロックを解除できず、同時に実行できないことを意味します.このスレッドが実行された後にロックを返した後、他のスレッドがロックを解除して実行することができます.このような状況は、通常、マルチスレッドが共通リソースにアクセスする場合に発生し、リソースが改ざんされたり失われたりすることを避けるために、1つのスレッドのみがアクセスを許可され、アクセス中に他のスレッドはアクセスできません.
class Test{
  public synchronized void methodA(){
    Thread t = Thread.currentThread();
    System.out.println(t+" A ~");
    Thread.sleep(5000);
    System.out.println("A !");
  }
  public synchronized void methodB(){
    Thread t = Thread.currentThread();
    System.out.println(t+" B ~");
    Thread.sleep(5000);
    System.out.println("B !");
  }
}

public class Lock{
  public static void main(String[] args){
    Test test = new Test();
    Thread t1 = new Thread(){
      public void run(){
        test.methodA();
      }
    };
    Thread t2 = new Thread(){
      public void run(){
        test.methodB();
      }
    };
    t1.start();
    t2.start();
  }
}