Java Road to God:Javaインタビューの準備(9)

記事のディレクトリ

5.マルチスレッド

5.1次のプログラムを実行した結果

public static void main(String[] args) {
    
    
     Thread t=new Thread(){
    
    
          public void run(){
    
    
          pong();
     }
}
t.run();
System.out.println("ping");
}
static void pong(){
    
    
      System.out.println("pong");
}

5.2実行可能なクラスを作成するために使用できるメソッドは次のうちどれですか

5.3 java.lang.ThreadLocalの機能と原理を説明します。プログラムがThreadLocalの使用を確認したリスト

効果:

マルチスレッドセーフ(スレッドセーフ)プログラムを作成することは困難です。スレッドがリソースを共有できるようにするには、共有リソースを慎重に同期する必要があります。同期には一定のパフォーマンス遅延が発生します。一方、同期を処理する場合は、また、デッドロックを回避するために、オブジェクトのロックと解放に注意してください。さまざまな要因により、マルチスレッドプログラムの作成が困難になっています。

マルチスレッド共有リソースの問題を別の角度から考えてみてください。リソースの共有は非常に難しいので、まったく共有しないでください。スレッドごとにリソースのコピーを作成してみませんか。各スレッドのデータへのアクセスの動作は分離されており、これを実現する方法は、各スレッドに特定のスペースを与えて、そのスレッド専用のリソースを維持することです。

例:Hibernateのセッションが使用されます。

ThreadLocalの原理

ThreadLocalは、各スレッドの変数のコピーをどのように維持しますか?実際、実装のアイデアは非常に単純です.ThreadLocalクラスには、各スレッドの変数のコピーを格納するために使用されるMapがあります。

5.4楽観的ロックと悲観的ロックについて話す

Pessimistic Lock(Pessimistic Lock)は、その名前が示すように、非常に悲観的です。データを取得するたびに、他の人がデータを変更すると思うので、データを取得するたびにロックするので、誰かがデータを取得すると、取得するまでブロックされます。ロックされます。このようなロックメカニズムの多くは、行ロック、テーブルロックなど、読み取りロック、書き込みロックなどの従来のリレーショナルデータベースで使用されており、これらはすべて操作前にロックされます。

オプティミスティックロック(オプティミスティックロック)は、その名前が示すように非常に楽観的です。データを取得するたびに、他の人がデータを変更しないと思うので、ロックされませんが、更新するときに、他の人が持っているかどうかを判断しますこの期間中にこれを更新しました。データについては、バージョン番号などのメカニズムを使用できます。楽観的ロックは、スループットを向上させることができるマルチ読み取りアプリケーションタイプに適しています。データベースがwrite_conditionと同様のメカニズムを提供する場合、それは実際には楽観的ロックです。

どちらのタイプのロックにも、それぞれ長所と短所があります。一方が他方よりも優れていると考えるべきではありません。たとえば、楽観的なロックは、書き込みが少ない場合、つまり競合がほとんど発生しない場合に適しているため、ロックのオーバーヘッドが節約されます。システムの全体的なスループット。ただし、競合が頻繁に発生する場合、上位レベルのアプリケーションは再試行を続行し、実際にはパフォーマンスが低下するため、この場合はペシミスティックロックを使用する方が適切です。

5.5 Javaでマルチスレッドを実装する方法は?スレッド状態の変化するプロセスを説明してください

複数のスレッドが同じデータにアクセスする場合、スレッドセーフの問題が発生する傾向があり、リソースが一度に1つのスレッドによってのみ使用されるようにするための何らかの方法が必要です。データの安全性を確保するためにスレッドを同期する必要があります。スレッド同期の実装:同期コードブロックと同期メソッド、どちらもsynchronizedキーワードを使用する必要があります

同期コードブロック:public void makeWithdrawal(int amt){

同期(acct){}

}

同期メソッド:public synchronized void makeWithdrawal(int amt){}

スレッド同期の利点:スレッドセーフの問題を解決する

スレッド同期のデメリット:パフォーマンスの低下によりデッドロックが発生する可能性があります

5.6 ThreadまたはRunnableを使用してマルチスレッドコードを記述し、2つの違いを教えてください。

方法1:Java.lang.Threadクラスを継承し、run()メソッドをオーバーライドします。長所:記述が簡単、短所:他の親クラスから継承できない

public class ThreadDemo1 {
    
    
public static void main(String args[]) {
    
    
MyThread1 t = new MyThread1();
t.start();
while (true) {
    
    
System.out.println("兔子领先了,别骄傲");
}
}
}
class MyThread1 extends Thread {
    
    
public void run() {
    
    
while (true) {
    
    
System.out.println("乌龟领先了,加油");
}
}
}

方法2:Java.lang.Runnableインターフェースを実装し、run()メソッドを実装します。利点:他のクラスを継承でき、複数のスレッドが同じThreadオブジェクトを共有できます。欠点:プログラミングメソッドは少し複雑です。現在のスレッドにアクセスする必要がある場合は、Thread.currentThread()メソッドを呼び出す必要があります。

public class ThreadDemo2 {
    
    
public static void main(String args[]) {
    
    
MyThread2 mt = new MyThread2();
Thread t = new Thread(mt);
t.start();
while (true) {
    
    
System.out.println("兔子领先了,加油");
}
}
}
class MyThread2 implements Runnable {
    
    
public void run() {
    
    
while (true) {
    
    
System.out.println("乌龟超过了,再接再厉");
}
}
}

5.7マルチスレッドプログラミングでのwaitメソッドの呼び出しメソッドは何ですか?

waitメソッドはスレッド通信のメソッドの1つであり、同期メソッドまたは同期コードブロックで使用する必要があります。そうしないと、例外がスローされます。これには「ロック」の概念が含まれ、waitメソッドはを使用して呼び出す必要があります。したがって、オブジェクトを保持しているロックは、ロックされたオブジェクトを使用してnotifyまたはnotifyAllメソッドが呼び出され、待機中のスレッドをウェイクアップして保持されているロックを解放するまで、スレッド待機状態になります。

5.8Javaスレッドのいくつかの状態

スレッドの6つの状態

  • 初期状態
    スレッドクラスは、Runnableインターフェースを実装し、Threadから継承することで取得できます。新しいインスタンスが発生すると、スレッドは初期状態になります。

  • 準備
    完了状態準備完了状態とは、実行する資格があることを意味します。スケジューラーがユーザーを検出しない場合は、常に準備完了状態になります。
    スレッドのstart()メソッドが呼び出され、スレッドは準備完了状態になります。
    現在のスレッドのsleep()メソッドが終了し、他のスレッドのjoin()が終了して、ユーザーの入力が完了するのを待ちます。スレッドはオブジェクトロックを取得し、これらのスレッドも準備完了状態になります。
    現在のスレッドのタイムスライスが使い果たされると、現在のスレッドのyield()メソッドが呼び出され、現在のスレッドは準備完了状態になります。
    ロックプール内のスレッドがオブジェクトロックを取得すると、準備完了状態になります。
    実行状態
    スレッドスケジューラが実行可能プールから現在のスレッドとしてスレッドを選択したときのスレッドの状態これは、スレッドが実行状態に入る唯一の方法でもあります。

  • ブロッキング状態
    ブロッキング状態は、synchronizedキーワード(ロックの取得)によって変更されたメソッドまたはコードブロックに入るときにスレッドがブロックされた状態です。

  • 待機中
    。この状態のスレッドにはCPU実行時間が割り当てられません。明示的にウェイクアップされるまで待機する必要があります。そうしないと、無期限に待機します。

  • 残業待機
    。この状態のスレッドにはCPU実行時間が割り当てられませんが、他のスレッドによってウェイクアップされるまで無期限に待機する必要はありません。一定の時間が経過すると、スレッドは自動的にウェイクアップします。

  • 終了状態
    スレッドのrun()メソッドが完了するか、メインスレッドのmain()メソッドが完了すると、終了したと見なされます。このスレッドオブジェクトは生きている可能性がありますが、別の実行スレッドではなくなりました。スレッドが終了すると、生まれ変わることはできません。
    終了したスレッドでstart()メソッドを呼び出すと、java.lang.IllegalThreadStateExceptionがスローされます。

  • 待機キュー
    objのwait()、notify()メソッドを呼び出す前に、objロックを取得する必要があります。つまり、synchronized(obj)コードセグメントに書き込む必要があります。

5.9 Javaマルチスレッドでは、次のどの方法でスレッドがブロック状態にならないか

ここに画像の説明を挿入

5.10 volatileキーワードはスレッドセーフを保証しますか?

できません。volatileは同期メカニズムを提供しますが、知識は弱い同期メカニズムです。強力なスレッドセーフが必要な場合は、同期も使用する必要があります。

Java言語は、変数の更新操作が他のスレッドに確実に通知されるように、より弱い同期メカニズム、つまり揮発性変数を提供します。変数が揮発性タイプとして宣言されると、コンパイラとランタイムは変数が共有されていることを認識します。そのため、変数に対する操作は他のメモリ操作と並べ替えられません。揮発性変数はレジスタにキャッシュされたり、他のプロセッサからは見えないため、揮発性変数を読み取るときは、常に最新の書き込み値が返されます。

1.volatileのメモリセマンティクスは次のとおりです。

揮発性変数を書き込むとき、JMMはスレッドに対応するローカルメモリ内の共有変数値をメインメモリにすぐにフラッシュします。

揮発性変数を読み取る場合、JMMはスレッドに対応するローカルメモリを無効にし、共有変数をメインメモリから直接読み取ります。

第二に、揮発性の最下層の実装メカニズム

volatileキーワードを使用したコードとvolatileキーワードを使用しないコードのアセンブリコードを生成すると、volatileキーワードを使用したコードに追加のロックプレフィックス命令が含まれることがわかります。

1.並べ替える場合、次の命令をメモリバリアの前の位置に並べ替えることはできません。

2.CPUのキャッシュをメモリに書き込みます

3.書き込みアクションにより、他のCPUまたは他のコアがそのキャッシュを無効にします。これは、新しく書き込まれた値を他のスレッドに表示するのと同じです。

5.11一般的に使用されるJavaマルチスレッド起動メソッドを書き留めてください。一般的に使用されるエグゼキュータスレッドプールにはいくつかの種類があります。

(1)Threadクラスを継承します

public class java_thread extends Thread{
    
    
    public static void main(String args[]) {
    
    
        new java_thread().run();
        System.out.println("main thread run ");
    }
    public synchronized  void run() {
    
    
        System.out.println("sub thread run ");
    }
}

(2)Runnableインターフェースを実装する

public class java_thread implements Runnable{
    
    
    public static void main(String args[]) {
    
    
        new Thread(new java_thread()).start();
        System.out.println("main thread run ");
    }
    public void run() {
    
    
        System.out.println("sub thread run ");
    }
}

Executorフレームワークでは、Executorの静的メソッドを使用して、一般的に使用される3種類のスレッドプールを作成できます。

1)FixedThreadPoolこのスレッドプールは、固定数のスレッドでスレッドプールを作成できます。

2)SingleThreadExecutorは、単一のワーカースレッドを使用するエグゼキューターです。

3)CachedThreadPoolは、「無制限」の容量を持つスレッドプールであり、必要に応じて新しいスレッドを作成します。

5.12 sleep **()およびwait()に関して、次のエラーの説明の1つは**です。

5.13プロセスとスレッドの違いは何ですか

プロセスは、特定のデータセットに対して特定の独立した機能を持つプログラムの実行中のアクティビティであり、プロセスは、リソースの割り当てとスケジューリングのためのシステムの独立したユニットです。

スレッドは、プロセスのエンティティであり、CPUのスケジューリングとディスパッチの基本単位です。これは、プロセスよりも小さく、独立して実行できる基本単位です。スレッド自体は、基本的にシステムリソースを所有せず、少数のリソースのみを所有します。操作には不可欠ですが(プログラムカウンター、レジスターとスタックのセットなど)、プロセスが所有するすべてのリソースを、同じプロセスに属する他のスレッドと共有できます。

5.14 n個の複数のスレッドを作成しますが、これらのスレッドが同時に開始するようにするにはどうすればよいですか?はっきりと見てください、それは「同時に」です

forループを使用してスレッドオブジェクトを作成し、同時にwait()メソッドを呼び出してすべてのスレッドを待機させます。最後のスレッドも準備ができるまで、notifyAll()を呼び出してすべてのスレッドを同時に開始します。

例:n台の車を提供し、それらすべてを同時にスタートラインから開始させます。Javaマルチスレッドでコードを作成するにはどうすればよいですか。

車にロックを追加し、対応するオペランドを変更するという考え方です。すべての準備が整っていない場合は、最後の車が到着するまでロックを解除して、すべてのレーシングスレッドをウェイクアップします。コードリファレンスは次のとおりです

public class CarCompetion {
    
    
    // 参赛赛车的数量
    protected final int totalCarNum = 10;
    // 当前在起跑线的赛车数量
    protected int nowCarNum = 0;
}
public class Car implements Runnable{
    
    
    private int carNum;
    private CarCompetion competion = null;
    public Car(int carNum, CarCompetion competion) {
    
    
        this.carNum = carNum;
        this.competion = competion;
    }
    @Override
    public void run() {
    
    
        synchronized (competion) {
    
    
            competion.nowCarNum++;
            while (competion.nowCarNum < competion.totalCarNum) {
    
    
                try {
    
    
                    competion.wait();
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
            competion.notifyAll();
        }
        startCar();
    }
    private void startCar() {
    
    
        System.out.println("Car num " + this.carNum + " start to run.");
        try {
    
    
            Thread.sleep(3000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("Car num " + this.carNum + " get to the finish line.");
    }
}
public static void main(String[] args) {
    
    
    CarCompetion carCompetion = new CarCompetion();
    final ExecutorService carPool =
        Executors.newFixedThreadPool(carCompetion.totalCarNum);
    for (int i = 0; i < carCompetion.totalCarNum; i++) {
    
    
        carPool.execute(new Car(i, carCompetion));
 
}

5.15スレッドはどのように通信しますか

1.同期。これは一般的に使用される同期キーワードです。このメソッドは基本的に共有変数です。最初にロックを取得した人が最初にロックを実行します。

2.whileループ。これも共有メモリに基づいて実装され、通常はvolatileキーワードと組み合わせて使用​​されます。マルチスレッド環境では、whileループを使用して、誤ったウェイクアップを防ぐための判断を下します。

3.通知/待​​機メソッド。

おすすめ

転載: blog.csdn.net/weixin_54707168/article/details/113975387