マルチスレッドの面接の質問の整理(回答付きの27の質問)

  1. プロセスとスレッドの違いについて話します。
    つまり、プロセスはプログラム操作とリソース割り当ての基本単位です。
    プログラムには少なくとも1つのプロセスがあり、プロセスには少なくとも1つのスレッドがあります。
    プロセスには独立したメモリユニットがあります。実行、および複数のスレッドがメモリリソースを共有するため、スイッチングの数が減り、効率が向上します。
    スレッドは、プロセスのエンティティであり、CPUのスケジューリングと割り当ての基本単位であり、プログラムよりも小さく、独立して実行できる基本単位です。同じプロセス内の複数のスレッドを同時に実行できます。

  2. デーモンスレッドを理解していますか?
    プログラムと非デーモンスレッドの違いは何ですか?プログラムの実行後、JVMは非デーモンスレッドが完了するのを待ってからシャットダウンしますが、JVMはデーモンスレッドを待ちません。最も古典的な例デーモンスレッドのはGCスレッドです。

  3. マルチスレッドコンテキストスイッチングとは何ですか?
    マルチスレッドコンテキストスイッチングとは、CPU制御が、すでに進行中のスレッドから、CPU実行権の取得の準備ができて待機している別のスレッドに切り替わるプロセスを指します。

  4. スレッドを作成するためのRunnableとThreadの違いは何ですか?
    Runnableインターフェースを実装する方が良い場合があります。
    2つの理由があります:
    (1)Javaは多重継承をサポートしていないため、Threadクラスを拡張すると、このサブクラスは他のクラスを拡張できず、Runnableインターフェイスを実装するクラスは別のクラスを拡張できます
    (2)クラスは実行可能のみである可能性があります。、したがって、Threadクラス全体を継承するオーバーヘッドが大きすぎます。

  5. RunnableとCallableの違い
    Runnableインターフェイスのrun()メソッド戻り値は無効です。これは、純粋にrun()メソッドのコードを実行することです
    。Callableインターフェイスのcall()メソッドには戻り値があります。 valueは汎用タイプであり、FutureおよびFutureTaskと組み合わせて使用​​して、非同期実行の結果を取得できます。
    マルチスレッドはシングルスレッドよりも難しく複雑であるため、これは実際には非常に便利な機能です。重要な理由は、マルチスレッドが未知数でいっぱいであるということです。スレッドは実行されましたか?スレッドはどのくらい実行されましたか?スレッドの実行時に期待するデータが割り当てられていますか?このマルチスレッドタスクの完了を待つだけでよいことを知ることは不可能です。ただし、Callable + Future / FutureTaskは、マルチスレッド操作の結果を簡単に取得でき、待機時間が長すぎて必要なデータを取得できない場合は、スレッドのタスクをキャンセルできます。

  6. デッドロックの条件
    (1)相互に排他的な条件:リソースは一度に1つのプロセスでのみ使用できます
    (2)要求および保持条件:プロセスがリソースの要求に応答してブロックすると、取得したリソースを保持します。
    (3)非剥奪条件:プロセスによってすでに取得されたリソースは、使い果たされる前に強制的に剥奪することはできません。
    (4)循環待機条件:複数のプロセス間で循環待機リソース関係が形成されます。

  7. wait()メソッドとnotify()/ notifyAllメソッドを同期ブロックで呼び出す必要がある理由
    これはJDKで必須であり、wait()メソッドとnotify()/ notifyAll()メソッドは呼び出す前にオブジェクトのロックを取得する必要があります。

  8. wait、notify、notifyAllがThreadクラスに配置されない
    理由明らかな理由は、JAVAによって提供されるロックがスレッドレベルではなくオブジェクトレベルであるためです。各オブジェクトには、スレッドを介して取得されるロックがあります。スレッドがいくつかのロックを待機する必要がある場合は、オブジェクトのwait()メソッドを呼び出すのが理にかなっています。wait()メソッドがThreadクラスで定義されている場合、スレッドがどのロックを待機しているかは明らかではありません。
    簡単に言うと、wait、notify、notifyAllはロックレベルの操作であるため、ロックはオブジェクトに属しているため、Objectクラスで定義されます。

  9. ブロックされたスレッドをウェイクアップする方法
    wait()、sleep()、またはjoin()を呼び出してスレッドがブロックされた
    場合、InterruptedExceptionをスローしてスレッドを中断し、ウェイクアップできます。スレッドでIOブロッキングが発生した場合、何もできません。 、IOはオペレーティングシステムによって実装されるため、Javaコードがオペレーティングシステムに直接アクセスする方法はありません。

  10. FutureTaskとは何ですか?
    実際、前述のように、FutureTaskは非同期操作タスクを表し、Callableの特定の実装クラスをFutureTaskに渡すことができます。これは、この非同期操作タスクの結果を待って、タスクが完了したかどうかを判断し、タスクをキャンセルします。など。もちろん、FutureTaskはRunnableインターフェースの実装クラスでもあるため、FutureTaskをスレッドプールに配置することもできます。

  11. スレッドに実行時例外がある場合はどうなりますか?
    例外がキャッチされない場合、スレッドは実行を停止します。
    もう1つの重要なポイントは、このスレッドがオブジェクトのモニターを保持している場合、オブジェクトモニターはすぐに解放されるということです。

  12. Javaにはどのような種類のロックがありますか?
    (1)スピンロック:JDK1.6以降、スピンロックはデフォルトで有効になっています。以前の観察に基づくと、共有データのロック状態は短時間しか持続しません。この短時間のスレッドの一時停止と再開は少し無駄なので、後でロックを要求するスレッドを許可するプロセスを次に示します。待機しばらくの間ですが、プロセッサの実行時間をあきらめないでください。ロックを保持しているスレッドをすぐに解放できるかどうかを確認してください。スレッドを待機させるには、スレッドにビジーループを実行させる必要があります。これはスピン操作です。jdk6の後、適応スピンロックが導入されました。つまり、待機イベントは修正されなくなりましたが、同じロックの最後のオプション時間とロック所有者の状態によって決定されます。
    (2)バイアスロック:JDK1の後に導入されたロックの最適化。目的は、競合することなくデータ同期プリミティブを排除することです。スレッドの実行パフォーマンスをさらに向上させます。バイアスされたロックは偏心バイアスです。つまり、ロックは最初に取得したスレッドにバイアスされます。後続の実行中に他のスレッドによってロックが取得されない場合、バイアスされたロックを保持しているスレッドは再度続行する必要はありません。 。同期します。バイアスされたロックは、同期によってプログラムのパフォーマンスを向上させることができますが、競合は発生しません。つまり、プログラムの実行に必ずしも有益であるとは限りません。プログラム内のほとんどのロックが複数の異なるスレッドによってアクセスされる場合、バイアスされたモードはい、特定の問題の特定の分析を前提として、バイアスされたロックを使用するかどうかを検討できます。
    (3)軽量ロック:ロックの取得と解放のパフォーマンスコストを削減するために、「バイアスロック」と「軽量ロック」が導入されたため、Java SE1.6には4つのロック状態があります。なしロック状態、バイアスロック状態、軽量ロック状態、重量ロック状態、競合により徐々にアップグレードしていきます。ロックはアップグレードできますが、ダウングレードすることはできません。つまり、部分ロックは軽量ロックにアップグレードでき、部分ロックにダウングレードすることはできません。

  13. スレッド間で
    オブジェクトを共有し、wait / notify / notifyAll、await / signal / signalAllを介してウェイクアップおよび待機することで、2つのスレッド間でデータを共有する方法で十分です。たとえば、キュ​​ーのブロックBlockingQueueは、設計されたスレッド間でデータを共有することです。

  14. wait()を正しく使用する方法は?ifまたはwhileを使用しますか?
    スレッドがCPUに実行を開始させると、他の条件が満たされない可能性があるため、wait()メソッドはループで呼び出す必要があります。したがって、処理する前に、条件が満たされているかどうかをループで確認することをお勧めします。以下は、waitメソッドとnotifyメソッドを使用する標準コードです。synchronized(
    obj){ while(condition has not hold)obj.wait(); //。(ここでは省略)


  15. スレッドローカル変数ThreadLocalとは何ですか?
    スレッドローカル変数は、スレッドに限定され、スレッド自体に属し、複数のスレッド間で共有されない変数です。Javaは、スレッドの安全性を実現する方法であるスレッドローカル変数をサポートするためのThreadLocalクラスを提供します。ただし、管理環境(Webサーバーなど)でスレッドローカル変数を使用する場合は注意が必要です。この場合、ワーカースレッドのライフサイクルは、アプリケーション変数のライフサイクルよりも長くなります。作業の完了後にスレッドローカル変数にyesまたはnoがない場合、Javaアプリケーションでメモリリークが発生するリスクがあります。

  16. ThreadLocalの役割は何ですか?
    簡単に言えば、ThreadLocalは時間のスペースを変更する方法です。データを分離するために各スレッドでThreadLocal.ThreadLocalMapが維持されます。データが共有されていない場合、スレッドセーフの問題は当然発生しません。

  17. 生産者/消費者モデルの役割は何ですか?
    (1)生産者の生産能力と消費者の消費能力のバランスを取り、システム全体の運用効率を向上させる。これが生産者モデルの最も重要な役割である。
    (2)付随的であるデカップリング生産者/消費者モデルの役割デカップリングとは、生産者と消費者の間のつながりが少ないことを意味します。つながりが少ないほど、相互の制約なしに独立して開発できるようになります。

  18. タスクを送信するときにスレッドプールキューがいっぱいになるとどうなりますか?
    制限のないキューであるLinkedBlockingQueueを使用する場合は、問題ではありません。LinkedBlockingQueueは、タスクを無期限に格納できる無限のキューと見なすことができるため、実行を待機するためにブロックキューにタスクを追加し続けます。制限のあるキュー
    を使用する場合キュー。たとえば、ArrayBlockingQueueの場合、タスクは最初にArrayBlockingQueueに追加され、ArrayBlockingQueueがいっぱいになると、拒否ポリシーRejectedExecutionHandlerを使用して完全なタスクが処理されます。デフォルトはAbortPolicyです。

  19. なぜスレッドプールを使用するのですか?
    スレッドの頻繁な作成と破棄を避け、スレッドオブジェクトの再利用を実現します。
    さらに、スレッドプールを使用すると、プロジェクトに応じて並行性の数を柔軟に制御することもできます。

  20. Javaで使用されるスレッドスケジューリングアルゴリズムとは何ですか?
    プリエンプティブ。
    スレッドのCPUが不足すると、オペレーティングシステムは、スレッドの優先度、スレッドの枯渇、およびその他のデータに基づいて合計優先度を計算し、実行のために次のタイムスライスをスレッドに割り当てます。

  21. Thread.sleep(0)の機能は何ですか?
    Javaはプリエンプティブスレッドスケジューリングアルゴリズムを使用しているため、優先度の低い一部のスレッドがCPU制御も取得できるようにするために、スレッドがCPUの制御を取得することがよくある場合があります。 、Thread.sleep(0)を使用して、オペレーティングシステムの操作を手動でトリガーし、タイムスライスを割り当てることができます。これは、CPU制御のバランスを取るための操作でもあります。

  22. CAS
    CASとは何ですか。フルネームはCompareand Swap、つまり、compare-replaceです。
    メモリ値V、古い期待値A、および変更される値Bの3つのオペランドがあるとします。期待値Aとメモリ値Vが同じである場合に限り、メモリ値はBに変更されます。 trueを返します。それ以外の場合は、何もせずにfalseを返します。もちろん、CASは揮発性変数と連携して、毎回取得される変数がメインメモリ内の最新の値になるようにする必要があります。そうしないと、特定のスレッドでは、古い期待値Aが常に定数値Aになります。 CAS操作が失敗した場合、成功することはありません。

  23. 楽観的ロックと悲観的ロックとは楽観
    的ロック:楽観的ロックは、競合が常に発生するとは限らないため、ロックを保持する必要はないと考えています。比較置換の2つのアクションは、変数を変更しようとするアトミック操作として使用されます。メモリ。失敗した場合競合があることを意味するため、対応する再試行ロジックが必要です。

ペシミスティックロック:ペシミスティックロックは常に競合が発生すると考えているため、リソースを操作するたびに、同期のように排他ロックを保持します。状況に関係なく、ロックがロックされているときにリソースを直接操作できます。

  1. ConcurrentHashMapの並行性とは何ですか?
    ConcurrentHashMapの同時実行性はセグメントのサイズです。デフォルトは16です。これは、最大16のスレッドがConcurrentHashMapを同時に操作できることを意味します。これは、Hashtableに対するConcurrentHashMapの最大の利点でもあります。いずれの場合も、Hashtableには2つあります。同時にハッシュテーブルを取得するスレッド。データ?


  2. ConcurrentHashMapの動作原理ConcurrentHashMapは、JDK1.6とJDK1.8で異なります。
    JDK1.6:ConcurrentHashMapはスレッドセーフですが、Hashtableと比較すると、スレッドセーフを実現する方法が異なります。
    Hashtableは、ハッシュテーブル構造をロックすることによるブロックタイプです。スレッドがロックを保持している場合、他のスレッドはブロックして、ロックが解放されるのを待つ必要があります。
    ConcurrentHashMapは、個別のロックメソッドを使用します。ハッシュテーブル全体をロックするのではなく、部分ロックを使用します。つまり、スレッドがこの部分ロックを占有しても、ハッシュテーブル内の他の場所への他のスレッドのアクセスには影響しません。
    特定の実装:ConcurrentHashMap内にセグメントがあります。
    JDK1.8の場合:ConcurrentHashMapはセグメント分離ロックを使用しなくなりましたが、同期の問題を解決するために楽観的ロックCASアルゴリズムを使用していますが、最下層は依然として配列+リンクリスト->赤黒木を実現しています。

  3. ++演算子スレッドはJavaで安全ですか?
    スレッドセーフな操作ではありません。これには、変数の値の読み取り、増加、メモリへの保存など、複数の命令が含まれます。このプロセスには、複数のスレッドの交差が含まれる場合があります。

  4. マルチスレッド開発のグッドプラクティスは何ですか?
    (1)スレッドに名前を付けます
    (2)同期の範囲を最小限に抑えます
    (3)最初にvolatileを使用します
    (4)wait and notify()の代わりに、可能な限り高レベルの同時実行ツールを使用して、BlockingQueueなどのスレッド通信を実装します、Semeaphore
    (5)同期コンテナーではなく並行コンテナーの使用を優先する
    (6)スレッドプールの使用を検討する

https://www.kancloud.cn/smartsean/android/1106143Android
インタビュードキュメント

おすすめ

転載: blog.csdn.net/ambitionLlll/article/details/115219364