ホームページ  >  記事  >  Java  >  収集する価値のある Java マルチスレッド面接の質問 (回答付き)

収集する価値のある Java マルチスレッド面接の質問 (回答付き)

青灯夜游
青灯夜游転載
2019-11-25 15:21:582300ブラウズ

この記事は、Java マルチスレッドに関する面接の質問と回答をまとめたものです。一定の参考価値があります。困っている友人は参考にしてください。皆さんのお役に立てれば幸いです。

収集する価値のある Java マルチスレッド面接の質問 (回答付き)

#スレッドとは何ですか?

スレッドは、オペレーティング システムが操作のスケジューリングを実行できる最小単位であり、プロセスに含まれ、プロセス内の実際の操作単位です。プログラマはこれをマルチプロセッサ プログラミングに使用でき、マルチスレッドを使用して計算負荷の高いタスクを高速化できます。たとえば、1 つのスレッドがタスクを完了するのに 100 ミリ秒かかる場合、10 個のスレッドを使用してタスクを完了するのにかかる時間はわずか 10 ミリ秒です。 Java は言語レベルでのマルチスレッドの優れたサポートを提供しており、これも優れたセールスポイントです。

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

スレッドはプロセスのサブセットです。プロセスには多数のスレッドを含めることができ、各スレッドは異なるタスクを並行して実行します。異なるプロセスは異なるメモリ空間を使用し、すべてのスレッドは同じメモリ空間を共有します。これをスタック メモリと混同しないでください。各スレッドには、ローカル データを保存するための独自のスタック メモリがあります。

3) Java でスレッドを実装するにはどうすればよいですか?

言語レベルでは 2 つの方法があります。 java.lang.Thread クラスのインスタンスはスレッドですが、実行するには java.lang.Runnable インターフェイスを呼び出す必要があります。スレッド クラス自体が呼び出される Runnable インターフェイスであるため、java.lang.Thread クラスを継承できます。または、Runnable インターフェイスを直接呼び出してオーバーライドし、スレッドを実装する run() メソッドを記述します。

4) ランナブルまたはスレッドを使用しますか?

この質問は、前の質問のフォローアップです。Thread クラスを継承するか、Runnable インターフェイスを呼び出すことでスレッドを実装できることは誰もが知っています。問題は、どちらの方法が優れているのかということです。いつ使用されますか? Java がクラスの多重継承をサポートしていないが、複数のインターフェースを呼び出すことはできることを知っていれば、この質問は簡単に答えることができます。したがって、他のクラスから継承したい場合は、当然、Runnable インターフェースを呼び出す必要があります。

6) Thread クラスの start() メソッドと run() メソッドの違いは何ですか?

この質問はよく聞かれますが、それでも面接官の Java スレッド モデルの理解を区別する可能性があります。 start() メソッドは、新しく作成されたスレッドを開始するために使用され、start() は内部で run() メソッドを呼び出します。これには、run() メソッドを直接呼び出す場合とは異なる効果があります。 run() メソッドを呼び出すと、元のスレッドでのみ呼び出されます。新しいスレッドが開始されていない場合は、start() メソッドによって新しいスレッドが開始されます。

7) Java における Runnable と Callable の違いは何ですか?

Runnable と Callable は両方とも、異なるスレッドで実行されるタスクを表します。 Runnable は JDK1.0 から利用可能であり、Callable は JDK1.5 で追加されました。それらの主な違いは、Callable の call() メソッドは値を返し、例外をスローできるのに対し、Runnable の run() メソッドにはこれらの機能がないことです。 Callable は、計算結果がロードされた Future オブジェクトを返すことができます。

8) Java における CyclicBarrier と CountDownLatch の違いは何ですか?

CyclicBarrier と CountDownLatch の両方を使用して、スレッドのグループを他のスレッドを待機させることができます。 CyclicBarrier とは異なり、CountdownLatch は再利用できません。

9) Java メモリ モデルとは何ですか?

Java メモリ モデルは、さまざまなメモリ アーキテクチャ、CPU、オペレーティング システム間で Java プログラムが決定論的に動作するように指定およびガイドします。これは、マルチスレッド状況では特に重要です。 Java メモリ モデルは、あるスレッドによって行われた変更が他のスレッドからも認識できること、およびそれらの間には優先関係があることを保証します。この関係は、プログラマーが同時にプログラミングする際により明確に考えることができるようにするためのいくつかのルールを定義します。たとえば、先読み関係により、

    スレッド内のコードが順番に実行されることが保証されます。これは、プログラム順序ルールと呼ばれます。
  • 同じロックの場合、ロック解除操作は、後で実行される別のロック操作の前に実行する必要があります。これは、モニター ロック ルールとも呼ばれます。
  • 前の揮発性書き込み操作は、次の揮発性読み取り操作に先行します。これは、揮発性変数ルールとも呼ばれます。
  • スレッド内の操作はすべて、このスレッドの start() 呼び出しの後に呼び出す必要があります。これはスレッド起動ルールとも呼ばれます。
  • スレッドのすべての操作は、スレッド終了ルールに従って、スレッドが終了する前に発生します。
  • オブジェクトの終了操作は、オブジェクトの構築後に完了する必要があります。オブジェクト終了ルールとも呼ばれます。
  • 移行性
Java メモリ モデルについての理解を深めるために、『Java 同時プログラミングの実践』の第 16 章を読むことを強くお勧めします。

10) Java の揮発性変数とは何ですか?

volatile は、メンバー変数でのみ使用できる特別な修飾子です。 Java 並行プログラムに同期クラスがない場合、メンバー変数に対するマルチスレッド操作は他のスレッドに対して透過的です。揮発性変数は、次の読み取り操作が前の書き込み操作の後に発生することを保証できます。これは、前の質問の揮発性変数のルールです。

11) スレッド セーフとは何ですか? Vector はスレッドセーフなクラスですか?

コードが配置されているプロセスで複数のスレッドが同時に実行されている場合、これらのスレッドがこのコードを同時に実行する可能性があります。各実行の結果がシングルスレッド実行の結果と同じであり、他の変数の値が予想どおり同じである場合、それはスレッドセーフです。スレッドセーフなカウンター クラスは、同じインスタンス オブジェクトが複数のスレッドで使用される場合でも計算エラーを引き起こしません。明らかに、コレクション クラスをスレッド セーフと非スレッド セーフの 2 つのグループに分けることができます。 Vector は同期メソッドを使用してスレッド セーフを実現しますが、それに似た ArrayList はスレッド セーフではありません。

12) Java の競合状態とは何ですか?例を挙げる。

競合状態は、同時実行条件下でプログラムにいくつかのバグを引き起こす可能性があります。競合状態は、複数のスレッドがリソースを奪い合うことで発生し、最初に実行するプログラムが競合に失敗して後から実行すると、プログラム全体に不確実なバグが発生します。このようなバグは、スレッド間のランダムな競合により発見が困難であり、再発することが困難です。

13) Java でスレッドを停止するにはどうすればよいですか?

Java は豊富な API を提供しますが、スレッドを停止するための API は提供しません。 JDK 1.0 には当初、stop()、suspend()、resume() などのいくつかの制御メソッドがありましたが、潜在的なデッドロックの脅威のため、後続の JDK バージョンでは非推奨になりました。その後、Java API の設計者は、互換性のあるスレッドを提供しませんでした。スレッドを停止する安全な方法。 run() または call() メソッドが実行されると、スレッドは自動的に終了します。スレッドを手動で終了したい場合は、揮発性のブール変数を使用して run() メソッドのループを終了するか、タスクをキャンセルしてスレッドを中断します。 。

14) スレッドの実行中に例外が発生した場合はどうなりますか?

これは、私が面接で遭遇した非常にトリッキーな Java 面接の質問です。簡単に言えば、例外がキャッチされない場合、スレッドは実行を停止します。 Thread.UncaughtExceptionHandler は、キャッチされなかった例外による突然のスレッド中断を処理するために使用される組み込みインターフェイスです。キャッチされない例外によってスレッドが中断される場合、JVM は Thread.getUncaughtExceptionHandler() を使用してスレッドの UncaughtExceptionHandler をクエリし、スレッドと例外をパラメータとしてハンドラの uncaughtException() メソッドに渡して処理します。

15) 2 つのスレッド間でデータを共有するにはどうすればよいですか?

これは、共有オブジェクトを通じて実現するか、ブロッキング キューなどの同時データ構造を使用して実現できます。このチュートリアル「Java スレッド間通信」(2 つのスレッド間でのオブジェクトの共有を含む) では、wait メソッドと Notice メソッドを使用して、プロデューサー/コンシューマー モデルを実装します。

16) Java の Notice と NotifyAll の違いは何ですか?

これも難しい質問です。複数のスレッドが 1 つの監視ロックを待機する可能性があるためです。Java API の設計者は、待機条件が変化したときに通知するメソッドをいくつか提供していますが、これらのメソッドは完全には機能していません。実装されました。 Notice() メソッドは特定のスレッドをウェイクアップできないため、スレッドが待機している場合にのみ役立ちます。また、notifyAll() はすべてのスレッドをウェイクアップし、少なくとも 1 つのスレッドが実行を継続できるようにロックを競合できるようにします。

17) wait、notify、notifyAll メソッドがスレッド クラスにないのはなぜですか?

これは、既存のシステムや、一般的だが不合理に見える事柄についての面接官の見解を検討する設計関連の質問です。これらの質問に答えるときは、これらのメソッドを Object クラスに配置することがなぜ意味があるのか​​、また、なぜ Thread クラスに配置しないのかを説明する必要があります。明白な理由は、JAVA によって提供されるロックがスレッド レベルではなくオブジェクト レベルであり、各オブジェクトにロックがあり、スレッドを通じて取得されるためです。スレッドが何らかのロックを待機する必要がある場合は、オブジェクト内で wait() メソッドを呼び出すのが合理的です。 wait() メソッドが Thread クラスで定義されている場合、スレッドがどのロックを待機しているかは明らかではありません。簡単に言えば、wait、notify、notifyAll はロックレベルの操作であり、ロックはオブジェクトに属するため、これらは Object クラスで定義されます。

18) ThreadLocal 変数とは何ですか?

ThreadLocal は Java の特殊変数です。各スレッドには ThreadLocal があります。つまり、各スレッドには独自の独立変数があり、競合状態は完全に排除されます。これは、作成にコストがかかるオブジェクトのスレッド セーフを実現する良い方法です。たとえば、ThreadLocal を使用して SimpleDateFormat をスレッド セーフにできます。そのクラスは作成にコストがかかり、呼び出しごとに異なるインスタンスを作成する必要があるため、このクラスを使用する価値はありません。ローカル スコープ これを使用して、各スレッドに変数の独自のコピーが提供されると、効率が大幅に向上します。まず、再利用により、作成される高価なオブジェクトの数が削減されます。 2 番目に、高価な同期や不変性を使用せずにスレッドの安全性が得られます。スレッド ローカル変数のもう 1 つの良い例は、ThreadLocalRandom クラスです。これは、マルチスレッド環境で作成するコストのかかる Random オブジェクトの数を減らします。

19) FutureTask とは何ですか?

Java 並行プログラムでは、FutureTask はキャンセル可能な非同期操作を表します。操作の開始とキャンセル、操作が完了したかどうかの問い合わせ、操作結果の取得などのメソッドがあります。結果は操作が完了した場合にのみ取得できます。操作が完了していない場合、get メソッドはブロックされます。 FutureTask オブジェクトは、Callable および Runnable を呼び出すオブジェクトをラップできます。FutureTask は Runnable インターフェイスも呼び出すため、実行のために Executor に送信できます。

20) Java の中断メソッドと isInterruptedd メソッドの違いは何ですか?

interrupted() と isInterrupted() の主な違いは、前者は割り込みステータスをクリアし、後者はクリアしないことです。 Java マルチスレッドの割り込みメカニズムは内部フラグを使用して実装されており、Thread.interrupt() を呼び出してスレッドを割り込むと、割り込みフラグが true に設定されます。割り込みスレッドが静的メソッド Thread.interrupted() を呼び出して割り込みステータスを確認すると、割り込みステータスはクリアされます。非静的メソッド isInterrupted() は、他のスレッドの割り込みステータスをクエリするために使用され、割り込みステータス識別子は変更されません。簡単に言うと、InterruptedException をスローするメソッドはすべて、割り込みステータスをクリアします。いずれの場合も、スレッドの割り込みステータスは、割り込みを呼び出す他のスレッドによって変更される可能性があります。

21) 同期ブロックで待機メソッドと通知メソッドが呼び出されるのはなぜですか?

主な理由は、Java API がこれを義務付けているためです。これを行わないと、コードは IllegalMonitorStateException をスローします。もう 1 つの理由は、待機と通知の間の競合状態を避けるためです。

22) ループ内で待機条件をチェックする必要があるのはなぜですか?

ループ内でチェックされていない場合、待機状態にあるスレッドが誤ったアラートや偽のウェイクアップを受信する可能性があります。終了条件が満たされない場合、プログラムは終了します。したがって、待機中のスレッドがウェイクアップした時点では、元の待機状態がまだ有効であるとは考えられず、notify() メソッドが呼び出されてから待機中のスレッドがウェイクアップするまでの間に、待機状態が変化する可能性があります。 Eclipse でテンプレートを作成して wait を呼び出し、それを試すように通知することができます。この問題について詳しく知りたい場合は、『Effective Java』という本のスレッドと同期の章を読むことをお勧めします。

23) Java における同期コレクションと同時コレクションの違いは何ですか?

同期コレクションと同時コレクションはどちらも、マルチスレッドと同時実行に適したスレッドセーフなコレクションを提供しますが、同時コレクションの方がよりスケーラブルです。 Java 1.5 より前は、プログラマは同期コレクションのみを使用できました。これにより、マルチスレッドの同時実行中に競合が発生し、システムのスケーラビリティが妨げられます。 Java5 では、ConcurrentHashMap のような同時コレクションが導入されました。これは、スレッドの安全性を提供するだけでなく、ロックの分離や内部パーティショニングなどの最新の技術によりスケーラビリティを向上させます。

24) Java におけるヒープとスタックの違いは何ですか?

この質問がマルチスレッドおよび同時実行の面接質問として分類されているのはなぜですか?スタックはスレッドと密接に関係するメモリ領域であるためです。各スレッドには独自のスタック メモリがあり、ローカル変数、メソッド パラメータ、およびスタック呼び出しを保存するために使用されます。あるスレッドに保存された変数は、他のスレッドには表示されません。ヒープは、すべてのスレッドによって共有される共通メモリ領域です。オブジェクトはすべてヒープ内に作成されます。効率を向上させるために、スレッドはオブジェクトをヒープから独自のスタックにキャッシュします。複数のスレッドがこの変数を使用すると、問題が発生する可能性があります。このとき、揮発性変数が影響する可能性があります。スレッドがメイン スタックから開始され、メモリから変数の値を読み取る必要があります。

25) スレッド プールとは何ですか?なぜそれを使うのでしょうか?

スレッドの作成には多くのリソースと時間がかかるため、タスクが来たときだけスレッドを作成すると応答時間が長くなり、プロセスで作成できるスレッドの数が制限されます。このような問題を回避するために、プログラム起動時に処理に応答するスレッドを複数用意し、これをスレッドプールと呼び、その中のスレッドをワーカースレッドと呼びます。 JDK1.5 以降、Java API はさまざまなスレッド プールを作成できるように Executor フレームワークを提供します。たとえば、単一のスレッド プールは一度に 1 つのタスクを処理します。固定数のスレッド プールまたはキャッシュ スレッド プール (有効期間の短いタスクが多いプログラムに適した拡張可能なスレッド プール)。

26) 生産者と消費者の問題を解決するコードをどのように記述するか?

実際には、解決するスレッドの問題の多くは、プロデューサー/コンシューマー モデルに属しており、1 つのスレッドが他のスレッドが消費するタスクを生成します。この問題を解決するには、スレッド間で通信する方法を知っておく必要があります。 。この問題を解決するには、待機と通知を使用する低レベルの方法がありますが、より良い方法は、セマフォまたは BlockingQueue を使用してプロデューサー/コンシューマー モデルを実装することであり、このチュートリアルではそれを実装します。

27) デッドロックを回避するにはどうすればよいですか?


Java マルチスレッドにおけるデッドロック
デッドロックとは、実行中に 2 つ以上のプロセスがリソースを競合することによって引き起こされる状況を指します。外力を加えずに前進することができます。デッドロックが発生するとプログラムがハングし、タスクを完了できなくなるため、これは深刻な問題です。デッドロックが発生するには、次の 4 つの条件を満たす必要があります:

  • 相互排他条件: 1 つリソースはプロセスでのみ使用できます。
  • リクエストとホールドの条件: リソースのリクエストによりプロセスがブロックされた場合、プロセスは取得したリソースを保持します。
  • 非剥奪条件: プロセスが取得したリソースは、使い果たされる前に強制的に剥奪することはできません。
  • ループ待ち条件: 複数のプロセス間で先頭から末尾までのループ待ちのリソース関係が形成されます。

デッドロックを回避する最も簡単な方法は、循環待機状態を防止し、フラグを設定してシステム内のすべてのリソースを並べ替え、すべてのプロセスが特定の順序 (昇順または降順) でリソースを適用する必要があることを規定することです。 ) デッドロックを回避するための操作を実行します。

28) Java におけるライブロックとデッドロックの違いは何ですか?

これは上記の質問の拡張です。ライブロックはデッドロックに似ています。違いは、ライブロックのスレッドまたはプロセスの状態が常に変化することです。ライブロックは特別な種類の飢餓状態と考えることができます。 。ライブロックの現実的な例は、狭い廊下で 2 人が出会い、お互いが通れるようにお互いを避けようとするが、避ける方向が同じであるため、最終的には誰も廊下を通れない場合です。簡単に言えば、ライブロックとデッドロックの主な違いは、前者ではプロセスの状態は変化する可能性がありますが、実行を継続できないことです。

29) スレッドがロックを所有しているかどうかを検出するにはどうすればよいですか?

電話インタビューに参加するまで、スレッドがロックを所有しているかどうかを検出できるとは知りませんでした。 java.lang.Thread には、holdsLock() というメソッドがあり、現在のスレッドが特定のオブジェクトのロックを保持している場合にのみ true を返します。

30) Java でスレッド スタックを取得するにはどうすればよいですか?

さまざまなオペレーティング システムの Java プロセスのスレッド スタックを取得する方法は複数あります。スレッド スタックを取得すると、JVM はすべてのスレッドのステータスをログ ファイルに保存するか、コンソールに出力します。 Windows では、Ctrl Break キーの組み合わせを使用してスレッド スタックを取得できます。Linux では、kill -3 コマンドを使用します。スレッド ID を操作する jstack ツールを使用して取得することもできます。また、jps ツールを使用して ID を検索することもできます。

31) スレッドのスタック サイズを制御するために JVM のどのパラメータが使用されますか?

この質問は非常に単純です。-Xss パラメータは、スレッドのスタック サイズを制御するために使用されます。スレッドのスタックサイズ。

32) Java における synchronizedLock と ReentrantLock の違いは何ですか?

Java は、これまで長い間、synchronized キーワードを介してのみ相互排他を実現できましたが、これにはいくつかの欠点がありました。たとえば、ロックの外側にメソッドやブロック境界を拡張したり、ロックを取得しようとしたときに途中でキャンセルしたりすることはできません。 Java 5 では、これらの問題を解決するために、Lock インターフェースを介したより複雑な制御が提供されます。 ReentrantLock クラスは Lock を実装します。Lock は同期と同じ同時実行性とメモリ セマンティクスを持ち、拡張可能です。

33) 3 つのスレッド T1、T2、および T3 があります。これらが順番に実行されることを確認するにはどうすればよいですか?

マルチスレッドでは、スレッドを特定の順序で実行する方法がたくさんあります。スレッド クラスの join() メソッドを使用して、一方のスレッドで別のスレッドを開始し、もう一方のスレッドで別のスレッドを開始することができます。スレッドはスレッドを完了して続行します。 3 つのスレッドの順序を確保するには、T1 が最初に終了し、T3 が最後に終了するように、最後のスレッドを最初に開始する必要があります (T3 が T2 を呼び出し、T2 が T1 を呼び出します)。

34) Thread クラスの yield メソッドの機能は何ですか?

Yield メソッドは、現在実行中のスレッド オブジェクトを一時停止し、同じ優先順位を持つ他のスレッドの実行を許可できます。これは静的メソッドであり、現在のスレッドが CPU 占有を放棄することのみを保証し、他のスレッドが CPU を占有できることは保証しません。yield() を実行するスレッドは、一時停止状態に入った直後に再度実行される可能性があります。

35) Java における ConcurrentHashMap の同時実行性は何ですか?

ConcurrentHashMap は、実際のマップをいくつかの部分に分割して、スケーラビリティとスレッドの安全性を実現します。この分割は同時実行性を使用して取得されます。同時実行性は、マルチスレッド状況での競合を避けるためのデフォルト値 16 を持つ ConcurrentHashMap クラス コンストラクターのオプションのパラメーターです。

36) Java のセマフォとは何ですか?

Java のセマフォは、カウント信号である新しい同期クラスです。概念的には、セマフォは許可されたコレクションを維持します。必要に応じて、各acquire()はパーミッションが利用可能になるまでブロックし、その後パーミッションを取得します。各 release() はアクセス許可を追加するため、ブロッキングしている取得者を解放する可能性があります。ただし、Semaphore は実際のライセンス オブジェクトを使用するのではなく、使用可能なライセンスの数のみをカウントし、適切なアクションを実行します。セマフォは、データベース接続プールなどのマルチスレッド コードでよく使用されます。

37) タスクを送信したときにスレッド プール キューがいっぱいの場合。会議が開催されると何が起こりますか?

これは難しい質問であり、多くのプログラマは、スレッド プール キューにスペースができるまでタスクはブロックされると考えるでしょう。実際、タスクの実行をスケジュールできない場合、ThreadPoolExecutor の submit() メソッドは RejectedExecutionException をスローします。

38) Java スレッド プールの submit() メソッドとexecute() メソッドの違いは何ですか?

どちらのメソッドもスレッド プールにタスクを送信できます。execute() メソッドの戻り値の型は Executor インターフェイスで定義されている void で、submit() メソッドは Future 保持を返すことができます。計算結果 ExecutorService インターフェイスで定義され、Executor インターフェイスを拡張するオブジェクト ThreadPoolExecutor や ScheduledThreadPoolExecutor などの他のスレッド プール クラスにはこれらのメソッドがあります。

39) ブロッキング方法とは何ですか?

ブロッキング メソッドは、プログラムが何もせずにメソッドの完了を待つことを意味します。ServerSocket の accept() メソッドは、クライアントの接続を待ちます。ここでのブロックとは、呼び出し結果が返される前に、現在のスレッドが一時停止され、結果が取得されるまで返されないことを意味します。さらに、タスクが完了する前に戻る非同期メソッドや非ブロッキング メソッドもあります。

40) Swing はスレッドセーフですか?なぜ?

Swing はスレッドセーフではないと確信を持って答えることができますが、たとえ面接官が理由を尋ねなかったとしても、その答えの理由を説明する必要があります。 Swing がスレッドセーフではないというとき、よくそのコンポーネントについて言及します。これらのコンポーネントはマルチスレッドでは変更できません。GUI コンポーネントへのすべての更新は AWT スレッドで完了する必要があり、Swing は 2 つのコールバック メソッドを提供します: 同期と非同期. 更新します。

41) Java の invokeAndWait と invokeLater の違いは何ですか?

これら 2 つのメソッドは、イベント ディスパッチ スレッドではなく現在のスレッドから GUI コンポーネントを更新するために、Swing API によって Java 開発者に提供されます。 InvokeAndWait() は、進行状況バーなどの GUI コンポーネントを同期的に更新します。進行状況が更新されたら、それに応じて進行状況バーも変更する必要があります。進行状況が複数のスレッドによって追跡される場合は、invokeAndWait() メソッドを呼び出して、イベント ディスパッチ スレッドにコンポーネントを更新するように要求します。 invokeLater() メソッドは、更新コンポーネントを非同期的に呼び出します。

42) Swing API のどのメソッドがスレッドセーフですか?

この質問では、スイングとスレッドの安全性についても言及されています。コンポーネントはスレッドセーフではありませんが、repaint()、revalidate() など、複数のスレッドから安全に呼び出すことができるメソッドがいくつかあります。 JTextComponent の setText() メソッドと JTextArea の insert() および append() メソッドもスレッドセーフです。

43) Java で不変オブジェクトを作成するにはどうすればよいですか?

この問題はマルチスレッドとは関係ないようですが、不変性はすでに複雑な並行プログラムを簡素化するのに役立ちます。不変オブジェクトは同期せずに共有できるため、オブジェクトへの同時アクセスの同期オーバーヘッドが軽減されます。ただし、Java には @Immutable アノテーションがありません。不変クラスを作成するには、コンストラクター メソッドを使用してすべてのメンバーを初期化し、変数のセッター メソッドを提供せず、すべてのメンバーをプライベートとして宣言する必要があります。これらのメンバーにアクセスするときは、getter メソッドでオブジェクト自体を直接返すのではなく、オブジェクトのクローンを作成してオブジェクトのコピーを返します。 Java でオブジェクトを不変にする方法に関する私の記事には詳細なチュートリアルが含まれているので、これを読めば自信が持てるでしょう。

44) Java の ReadWriteLock とは何ですか?

一般に、読み取り/書き込みロックは、同時実行プログラムのパフォーマンスを向上させるために使用されるロック分離テクノロジの結果です。 Java の ReadWriteLock は、Java 5 の新しいインターフェイスです。ReadWriteLock は、関連付けられたロックのペアを維持します。1 つは読み取り専用操作用、もう 1 つは書き込み用です。書き込みスレッドが存在しない場合、読み取りロックは複数の読み取りスレッドによって同時に保持される可能性があります。書き込みロックは排他的です。JDK の ReentrantReadWriteLock を使用してこのルールを実装できます。最大 65535 個の書き込みロックと 65535 個の読み取りロックがサポートされます。

45) マルチスレッドにおけるビジー ループとは何ですか?

ビジー ループとは、従来の方法とは異なり、プログラマがループを使用してスレッドを待機させることです。 wait()、sleep()、yield() はすべて CPU 制御を放棄しますが、ビジー ループは CPU を放棄せず、空のループを実行します。これの目的は、CPU キャッシュを保存することです。マルチコア システムでは、待機中のスレッドがウェイクアップ時に別のコアで実行され、キャッシュが再構築されることがあります。キャッシュの再構築を回避し、再構築の待ち時間を短縮するために使用できます。

46) 揮発性変数とアトミック変数の違いは何ですか?

これは興味深い質問です。まず、揮発性変数とアトミック変数は似ていますが、機能が異なります。揮発性変数は先読み関係、つまり、後続の読み取り操作の前に書き込み操作が発生することを保証できますが、アトミック性は保証されません。たとえば、カウント変数が volatile で変更された場合、カウント操作はアトミックではありません。 AtomicInteger クラスによって提供されるアトミック メソッドを使用すると、この操作をアトミックにできます。たとえば、getAndIncrement() メソッドは、現在の値に 1 を加算するインクリメント操作をアトミックに実行します。同様の操作は、他のデータ型や参照変数に対しても実行できます。

47) 同期ブロック内のスレッドが例外をスローした場合はどうなりますか?

この質問は多くの Java プログラマーを悩ませてきました。この質問に答えるためにロックが解放されるかどうかの手がかりを考えることができれば、正しく答えられる可能性があります。同期ブロックが正常に終了しても異常終了しても内部のスレッドがロックを解除してくれるので、ロックインターフェースに比べてロックの解除にエネルギーを費やさなくて済む同期ブロックの方が好みです。 finally ブロックでロックを解放します。

48) シングルトン モードのダブル チェック ロックとは何ですか?

この質問は Java の面接でよく聞かれますが、この質問への回答に対する面接官の満足度はわずか 50% です。半分の人はダブルチェック ロックを作成できず、半分の人はその隠れた危険性と Java 1.5 でそれを修正する方法を説明できません。これは実際には、スレッドセーフなシングルトンを作成するために使用される古いメソッドです。シングルトン インスタンスが最初に作成されるとき、パフォーマンスの最適化のために単一のロックを使用しようとしますが、JDK1.4 では複雑すぎるため失敗します。私は個人的には使用しません。それも好きじゃない。とにかく、よく聞かれることなので、嫌いな人でも知っておいて損はありません。

49) Java でスレッドセーフなシングルトンを作成するにはどうすればよいですか?

これは上記の質問のフォローアップです。二重チェック ロックが好きではなく、インタビュアーがシングルトン クラスを作成する代わりの方法について尋ねた場合は、JVM のクラス ロードと静的変数初期化機能を使用してシングルトン インスタンスを作成するか、列挙型を使用してシングルトンを作成する場合、私はこの方法が好きです。

50) あなたが従うマルチスレッドのベスト プラクティスを 3 つ書いてください

この種の質問は私のお気に入りです。あなたはパフォーマンスを向上させるために同時実行コードを作成していると思います。実践も行われます。ほとんどの Java プログラマーが従うべきだと私が考える 3 つのベスト プラクティスを次に示します。

  • スレッドに意味のある名前を付けます。
    これにより、バグの発見や追跡が容易になります。 OrderProcessor、QuoteProcessor、または TradeProcessor は、Thread-1、Thread-2、Thread-3 よりも優れた名前です。スレッドに、完了したいタスクに関連した名前を付けます。すべての主要なフレームワークと JDK も、このベスト プラクティスに従っています。
  • ロックを回避し、同期の範囲を減らす
    ロックは高価であり、コンテキストの切り替えにはより多くの時間とスペースが必要です。クリティカル セクションを減らすために、同期とロックの使用を最小限に抑えるようにしてください。したがって、私は同期メソッドよりも同期ブロックを好みます。これにより、ロックを完全に制御できるようになります。
  • 同期クラスを増やし、待機と通知の使用を減らす
    まず第一に、CountDownLatch、Semaphore、CyclicBarrier、Exchanger などの同期クラスはコーディング操作を簡素化しますが、wait を使用して複雑な制御フローを制御するのは困難ですそして通知します。第 2 に、これらのクラスは最高の企業によって作成および保守されており、後続の JDK で継続的に最適化および改善されます。これらの高レベルの同期ツールを使用すると、プログラムを簡単に最適化できます。
  • 同時コレクションを多く使用し、同期コレクションの使用を減らす
    これは、簡単に実行でき、大きなメリットがあるもう 1 つのベスト プラクティスです。同時コレクションは同期コレクションよりもスケーラビリティが高いため、同時にプログラミングする場合は同時コレクションを使用してください。 . より良い結果が得られます。次回マップを使用する必要がある場合は、まず ConcurrentHashMap の使用を検討する必要があります。

51) スレッドを強制的に開始するにはどうすればよいですか?

この質問は、Java ガベージ コレクションを強制する方法のようなものです。現在、方法はありません。System.gc() を使用してガベージ コレクションを実行できますが、成功する保証はありません。 Java ではスレッドを強制的に開始する方法はありません。スレッドはスレッド スケジューラによって制御され、Java は関連する API を公開しません。

52) Java のフォーク結合フレームワークとは何ですか?

フォーク結合フレームワークは、JDK7 で登場した効率的なツールで、Java 開発者はこれを使用して、最新のサーバー上のマルチプロセッサを最大限に活用できます。これは、利用可能な処理能力をすべて使用してプログラムのパフォーマンスを向上させるために、多くのサブモジュールに再帰的に分割できるアプリケーション向けに特別に設計されています。フォーク ジョイン フレームワークの大きな利点は、ワークスチール アルゴリズムを使用していることです。より多くのタスクを完了できるワーカー スレッドは、他のスレッドからタスクを盗んで実行できます。

53) Java マルチスレッドでの wait() メソッドと sleep() メソッドの呼び出しの違いは何ですか?

Java プログラムの待機とスリープは両方とも何らかの形式の一時停止を引き起こし、さまざまなニーズを満たすことができます。 wait() メソッドはスレッド間通信に使用されます。待機条件が true で他のスレッドが起動されている場合はロックが解放されますが、sleep() メソッドは CPU リソースを解放するか、現在のスレッドを一定期間停止するだけです。時間はかかりますが、ロックは解除されません。

Java 関連の面接の知識について詳しくは、Java 面接の質問 列をご覧ください。

以上が収集する価値のある Java マルチスレッド面接の質問 (回答付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。