Java Advanced-Multithreading

1.プログラム、プロセス、スレッドについての理解について話す

手順:特定のタスクを実行するために特定の言語で記述された一連の指示。静的コード
プロセスを指します。プログラム実行プロセスであり、実行中のプログラムです。リソース割り当ての単位として
Thread:はプログラム内の実行パスです。スケジューリングと実行の最小単位として、各スレッドには独立した実行スタックとプログラムカウンター(pc)があります。

2.スレッド

スレッドは、軽量プロセスとも呼ばれるjvmスケジューリングの最小単位です。プロセスはスレッドで構成されます。スレッドはプライベートプログラムテクノロジーとスタックを備えており、ヒープ内の共有リソースにアクセスできます。

3.複数のスレッドの作成

3.0スレッド宣言サイクル

新しい状態:
newキーワードとThreadクラスまたはそのサブクラスを使用してスレッドオブジェクトを作成すると、スレッドオブジェクトは新しい状態になります。プログラムがこのスレッドを開始()するまで、この状態のままです。

準備
完了状態:スレッドオブジェクトがstart()メソッドを呼び出すと、スレッドは準備完了状態になります。準備完了状態のスレッドは準備キューにあり、JVMのスレッドスケジューラによるスケジュールを待機しています。

実行中の状態:
準備完了状態のスレッドがCPUリソースを取得する場合、run()を実行でき、スレッドは現在実行中の状態です。実行状態のスレッドは最も複雑で、ブロックされ、準備ができて、停止する可能性があります。

ブロッキング状態:
スレッドがスリープ、サスペンドなどのメソッドを実行し、占有されたリソースを失った後、スレッドは実行状態からブロッキング状態に入ります。スリープ時間が経過した後、またはデバイスリソースを取得した後で、準備完了状態に再び入ることができます。3つのタイプに分けることができます:

ブロッキング待ち:実行状態のスレッドは、wait()メソッドを実行して、スレッドをブロッキング待ち状態に移行させます。

同期ブロッキング:スレッドは同期ロックの取得に失敗します(ロックが他のスレッドによって占有されているため)。

その他のブロッキング:スレッドのスリープ()または結合()を呼び出してI / O要求が発行されると、スレッドはブロッキング状態になります。sleep()状態がタイムアウトになると、join()はスレッドの終了またはタイムアウトを待機するか、I / O処理が完了し、スレッドが再び準備状態になります。

デッド状態:
実行状態のスレッドがタスクを完了するか、他の終了条件が発生すると、スレッドは終了状態に切り替わります。ここに画像の説明を挿入

3.1、Threadクラスから継承
  • 1. Threadクラスから継承するサブクラスを作成します
  • 2.スレッドの実行()を書き換えます—>このスレッドによって実行された操作を実行()で宣言します
  • 3. Threadクラスのサブクラスのオブジェクトを作成する
  • 4.オブジェクトを介してstart()を呼び出します。①現在のスレッドを開始します②現在のスレッドのrun()を呼び出します
//1.创建一个继承于Thread类的子类
class MyThread extends Thread {
   //2.重写Thread的run()

   @Override
   public void run() {
       for (int i = 0; i < 100; i++) {
           if (i % 2 == 0) {
               System.out.println(Thread.currentThread().getName() + ":" + i);
           }
       }
   }
}


public class ThreadTest {
   public static void main(String[] args) {
//        3.创建Thread类的子类的对象
       MyThread t1 = new MyThread();
       //4.通过对象调用start()
       t1.start();
//        t1.run();错误的

       //如下方法任在主线程中进行的
       for (int i = 0; i < 100; i++) {
           if (i % 2 == 0) {
           //获取当前的线程名
               System.out.println(Thread.currentThread().getName() + ":" +i + "*************main()**********");
           }
       }
   }
}

3.2方法2:Runnableインターフェースを実装する
  • 1. Runnableを実装するクラスを作成します
  • 2. Runnnable、run()の抽象メソッドを実装する実装クラス
  • 3.クラスを実装するオブジェクトを作成します
  • 4.このオブジェクトをパラメーターとしてThreadクラスのコンストラクターに渡し、Threadクラスのオブジェクトを作成します。
  • 5. Threadクラスのオブジェクトを介してstart()を呼び出す
//1.创建一个实现了Runnable的类
class MThread implements Runnable {

   @Override
   public void run() {
       for (int i = 0; i < 100; i++) {
           if (i % 2 == 0) {
               System.out.println(Thread.currentThread().getName() + ":" + i);
           }
       }
   }
}

public class ThreadTest1 {
   //     3.创建实现类的对象
   public static void main(String[] args) {
       MThread mThread = new MThread();
       //4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
       Thread t1 = new Thread(mThread);
       t1.setName("线程1");
//        5.通过Thread类的对象调用start()①启动线程②调用当前线程的run();-->调用了Runnable类型的target
       t1.start();
       //在开启一个线程
       Thread t2 = new Thread(mThread);
       t2.setName("线程2");
       t2.start();
   }
}


3.3 2つの問題を説明する:

質問1:スレッドを開始します。start()メソッドを呼び出す必要があります。スレッドを開始するためにrun()メソッドを呼び出すことはできません。
質問2:別のスレッドを開始する場合は、Threadサブクラスのオブジェクトを再作成し、start()を呼び出す必要があります。)メソッド

3.4スレッドの一般的なメソッド
  • 1.start():現在のスレッドを開始し、現在のスレッドのrun()を呼び出します

  • 2.run():通常、このメソッドをThreadクラスでオーバーライドし、このメソッドで作成されたスレッドによって実行される操作を宣言する必要があります

  • 3.currentThread():静的メソッド、現在のコードを実行するスレッドを返します

  • 4.getName():現在のスレッドの名前を取得する

  • 5.setName():現在のスレッドの名前を設定します

  • 6. yield():現在のCPU実行権を解放する

  • 7.join():スレッドaではスレッドbのjoin()メソッドが呼び出され、このときスレッドaはブロック状態になり、スレッドaはスレッドbの実行が完了するまでブロック状態を終了しません。

  • 8.stop():現在のスレッドを強制的に終了する、推奨されない、古い

  • 9.sleep(長いミリタイム):現在のスレッドをスリープ(ブロック)させ、ミリ秒数を指定します。現在のスレッドはミリ秒の時間内にブロックされます

  • 1. isAlive():現在のスレッドが生きているかどうかを判断します

  • スレッドの優先順位

  • MAX_PRIORITY:10

  • MIN_PRIORITY:1

  • NORM_PRIORITY:5つのデフォルトの優先度

  • 2.スレッドの優先順位を取得および設定する方法:

  • getPriority():スレッドの優先度を取得します

  • setPriority(int p):スレッドの優先度を設定します

    说明:高优先级的线程要抢占低优先级的CPU的执行权,但是只是概率上来讲,高优先级的线程高概率下被执行,并不一定高优先级的线程执行完后,低优先级才执行
    
3.5例:チケットを購入するための3つのウィンドウを作成し、チケットの総数は100、Runableインターフェースを使用

class Window extends Thread implements  Runnable {
   private static int ticket = 100;
   Object obj = new Object();
   @Override
   public void run() {
       while (true) {
       //解决线程安全问题
           synchronized (obj){
               if (ticket > 0) {

                   try {
                       Thread.sleep(100);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }

                   System.out.println(Thread.currentThread().getName() + ":买票,票号为:" + ticket);
                   ticket--;
               } else {
                   break;
               }
           }
       }
   }

}

public class WindowTest {

   public static void main(String[] args) {
       Window w = new Window();

       Thread t1 = new Thread(w);
       Thread t2 = new Thread(w);
       Thread t3 = new Thread(w);
       t1.setName("窗口1");
       t2.setName("窗口2");
       t3.setName("窗口3");

       t1.start();
       t2.start();
       t3.start();
   }

}

上記の操作にはスレッド解決の問題があり、解決する必要があります

  • 1。チケットを購入する過程で、重いチケットと間違ったチケットがありました

  • 2.問題の原因:スレッドがチケットを操作するとき、操作はまだ完了していません。他のスレッドが参加してチケット購入を操作します

  • 3.解決方法:スレッドaがチケットを操作しているとき、他のスレッドは参加できず、スレッドaがチケットの操作を完了するまで他のスレッドは参加しません。

  • スレッドaがブロックされていても、チケットの操作を開始できます。変更することはできません。

  • 4. Javaの同期メカニズムを通じてスレッドセーフティの問題を解決する

  • 方法1:同期コードブロック(同期モニター){

  • //需要被同步的代码
    
  • }
    説明:1.共有データを操作するためのコードは、同期する必要があるコードです

    2.共有データ:複数のスレッドによって操作される変数

    3.同期モニター:通称:ロック。どのクラスのオブジェクトもロックとして機能できます

    要件:複数が同じロックを共有する必要があります*補足:Runableを使用してマルチスレッドを作成する方法では、これを同期モニターとして使用することを検討できます。

    Threadクラスを使用してスレッドを作成する方法では、これを同期モニターとして使用する必要があります。現在のクラスを同期モニターとして使用することを検討できます。

方法2:同期方法

共有データを操作するためのコードがメソッドで完全に宣言されている場合、メソッド宣言を同期させることができます。

5.同期メソッドの使用は、スレッドの安全性の利点の問題を解決します

同期コードを操作するときは、1つのスレッドのみが参加し、他のスレッドは待機します。これは、シングルスレッドプロセスと同等であり、非効率的です

スレッドセーフティの問題3を解決:ロックlock-JDK5.0 new

3.6。同期メカニズムを使用して、シングルトンモードのレイジースタイルをスレッドセーフに書き換えます

1.インタビューの質問:同期とロックの類似点と相違点は何ですか
*

  • 同じ点:スレッドのセキュリティ問題を解決する
  • 異なる:同期メカニズムは、対応する同期コードを実行した後、同期モニターを自動的に解放します
  •  lock需要手动开启同步(lock()),同时结束同步也需要手动的实现(unlock());
    

* 2.優先順位:柔軟性の低下

  • ロックロック->同期コードブロック(すでにメソッド本体に入っており、対応するリソースが割り当てられています)---->同期メソッド(メソッド本体の外)
  • ロックが同期モニターにまだ存在するかどうか、存在しない場合、ロックは同期モニターと同等です
public class BankTest {
  private BankTest() {

  }

  private static BankTest instance = null;

  public static BankTest getInstance() {
      //方式一:效率稍差
//        synchronized (BankTest.class) {
//
//            if (instance == null) {
//                instance = new BankTest();
//            }
//            return instance;
//        }
      //方式二:效率更高
      if (instance == null){
          synchronized (BankTest.class){
              if (instance ==null){
                  instance = new BankTest();
              }
          }
      }
      return instance;
  }
}
3.7。デモスレッドのデッドロック
  • 1.デッドロックの理解:異なるスレッドが互いに必要とする異なるリソースを占有し、あきらめない、

  • スレッドデッドロックを形成して、他のパーティが必要な同期リソースを放棄するのを待っている

  • 2.説明:

  • デッドロックが発生した後、例外やプロンプトはありませんが、すべてのスレッドがブロックされ、続行できません

public class ThreadTest {
   public static void main(String[] args) {

       StringBuffer s1 = new StringBuffer();
       StringBuffer s2 = new StringBuffer();


       new Thread() {
           @Override
           public void run() {
               synchronized (s1) {
                   s1.append("a");
                   s2.append("1");
                   try {
                       Thread.sleep(100);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }

                   synchronized (s2) {
                       s1.append("b");
                       s2.append("2");

                       System.out.println(s1);
                       System.out.println(s2);

                   }
               }

           }
       }.start();

       new Thread(new Runnable() {
           @Override
           public void run() {
               synchronized (s2) {
                   s1.append("c");
                   s2.append("3");
                   try {
                       Thread.sleep(100);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }

                   synchronized (s1) {
                       s1.append("d");
                       s2.append("4");

                       System.out.println(s1);
                       System.out.println(s2);

                   }
               }
           }
       }).start();
   }
}

4.スレッド通信

スレッド通信の例:2つのスレッドを使用して1-100、スレッド1とスレッド2、相互印刷を印刷する

設計された3つのメソッド:同期コードブロックと同期メソッドでのみ表示できます

  • wait():このメソッドが実行されると、現在のスレッドはブロッキング状態に入り、同期モニターを解放します
  • notify():このメソッドが実行されると、待機によってブロックされたスレッドを起動します。待機しているスレッドが複数ある場合は、優先度の高いスレッドを起動します
  • notifyAll():このメソッドが実行されると、beiwaitによってブロックされたすべてのスレッドが呼び起こされます。
説明:

注:1.同期コードブロックと同期メソッドでは、3つのメソッドすべてを使用する必要があります
2.これらの3つのメソッドの呼び出し元は、同期コードブロックまたは同期メソッドの同期モニターである必要があります。
そうしないと、例外エラーが発生し
ます。3.これらの3つのメソッドは、java.lang.Objectで定義されています。

  • コードブロックの同期には、モニターの同期とデータの共有が含まれます。
  • 同期(同期モニター){
  • データを操作するためのコードは、データの操作の過程でそれが単一のスレッドであり、スレッドの安全性の問題がないことを保証します。
  • }
  • 複数のスレッドが共同で操作するデータ:共有データ。別のスレッドがスレッド操作に参加すると、スレッドの安全性の問題が発生します
インタビューの質問:睡眠と待機の類似点と相違点
  • 同じ点:実行メソッドが現在のスレッドをブロッキング状態にできると、
  • 違い:1. 2つのメソッド宣言の位置が異なります。sleep()はThreadクラスで宣言され、wait()はObjectクラスで宣言されています
  • 2.呼び出し要件は異なります。必要なシナリオでは、sleep()を呼び出すことができます。wait()は、同期コードブロックと同期メソッドでのみ使用できます
  • 3.同期モニターを解放するかどうかの質問:同期コードブロックと同期メソッドで2つのメソッドが使用されている場合、スリープはロックを解放せず、待機()は
class Number implements  Runnable{
   private int number =1;

   @Override
   public void run() {
       while (true){
           synchronized (this) {
               //让线程进入就绪状态
               notify();

               if (number <= 100){
                   try {
                       Thread.sleep(10);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
                   System.out.println(Thread.currentThread().getName() +":" + number);
                   number++;

                   try {
                       //使得调用如下wait()方法的线程,进入阻塞状态
                       wait();
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }

               }else {
                   break;
               }
           }
       }
   }
}
public class CommunicationTest {
   public static void main(String[] args) {
       Number m1 = new Number();
       Thread t1 = new Thread(m1);
       Thread t2 = new Thread(m1);

       t1.setName("线程1");
       t2.setName("线程2");

       t1.start();
       t2.start();

   }
}

5.スレッドを作成する3つの方法:Callableインターフェースの実装---- JDK5.0 new

  • 1. Callableインターフェースを実装する実装クラスを作成します
  • 2. call()メソッドを実装し、このスレッドがcall()で実行する必要がある操作を宣言します。
  • 3. Callableインターフェース実装クラスのオブジェクトを作成します
  • 4.この呼び出し可能な実装クラスのオブジェクトをFutureTaskコンストラクターに渡して、FutureTasのオブジェクトを作成します。
  • 5. FutureTaskのオブジェクトをパラメーターとしてThreadクラスのコンストラクターに渡し、Threadクラスのオブジェクトを作成して、start()メソッドを呼び出します。
  • 6.戻り値としてCallableの呼び出し可能なメソッドを取得する
  • Callableインターフェースを実装してマルチスレッドを作成する方法を理解している場合、Runnableインターフェースによるマルチスレッドよりも強力です。
  • 1.call()は戻り値を持つことができます
  • 2.call()は例外をスローし、外部操作によってキャッチされて、例外情報を取得できます。
  • 3Callableはジェネリックをサポートします
//1.创建一个实现Callable接口的实现类
class  NumThread implements Callable {
//2.实现call()方法,将此线程需要执行的操作声明在call()中
   @Override
   public Object call() throws Exception {
       int sum = 0;
       for (int i = 1; i <= 100; i++) {
           if (i % 2 == 0) {
               sum += i;
               System.out.println(i);
           }
       }
       return sum;
   }

}

public class ThreadNew {
   public static void main(String[] args) {
//        3.创建一个Callable接口实现类的对象
       NumThread numThread = new NumThread();
//        4.将此callable实现类的对象传递到FutureTask构造器中,创建FutureTas的对象
       FutureTask futureTask = new FutureTask(numThread);
//        5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread类的对象,调用start()方法
       new Thread(futureTask).start();

       try {
//            6.获取Callable中call的方法作为返回值
           //get()的返回值,即为FutureTask构造器参数Callable实现重写的call的返回值
           Object sum = futureTask.get();
           System.out.println("总和为:"+sum);
       } catch (InterruptedException e) {
           e.printStackTrace();
       } catch (ExecutionException e) {
           e.printStackTrace();
       }

   }
}

6.スレッドを作成する4つの方法:スレッドプールを使用する

メリット:

  • 1.応答速度を改善する(新しいスレッドを作成する時間を短縮)
  • 2.リソース消費を削減します(スレッドプールでスレッドを再利用します。毎回作成する必要はありません)
  • 3.簡単なスレッド管理
  • corePoolsize:コアプールのサイズ
  • maximumPoolSize:スレッドの最大数
  • keepAliveTime:スレッドが終了するまでの保持時間
class NumberThread implements Runnable {

   @Override
   public void run() {
       for (int i = 0; i < 100; i++) {
           if (i % 2 == 0) {
               System.out.println(Thread.currentThread().getName() + ":" + i);
           }
       }
   }
}

public class ThreadPool {
   public static void main(String[] args) {
       //提供指定线程数量的线程池
       ExecutorService service = Executors.newFixedThreadPool(10);

       //设置线程池的属性
       System.out.println(service.getClass());
       //2.执行指定的线程操作/需要提供Runnable接口或Callable接口实现类的对象
       //        service.submit(Callable callable)//提交,适用于Callable接口
       service.execute(new NumberThread());//适用于Runnable接口
       //3.关闭线程池
       service.shutdown();
   }

}

元の記事を19件公開しました 賞賛されました0 訪問数492

おすすめ

転載: blog.csdn.net/weixin_43244120/article/details/105010437