Java Multithreadingとは何ですか
Javaは、複数のタスクを同時に(同時に独立して)処理するメカニズムを提供します。同じJVMプロセスで複数のスレッドが共存するため、同じメモリ空間を共有します。複数のプロセスと比較して、複数のスレッド間の通信は軽量です。私の理解では、Java Multithreadingは完全にCPUの利用を改善することです。 Javaスレッドには、新しい、実行可能、ブロックされた、および死んでいる4つの状態があります。キーはブロックです。ブロッキングとは、待つことを意味します。ブロッキングスレッドは、スレッドディスパッチャーの時間スライス割り当てに関与しないため、当然CPUは使用しません。マルチスレッド環境では、これらのブロックされていないスレッドが実行され、CPUを最大限に活用します。
40の質問の概要
1.マルチスレッドの使用は何ですか?
多くの人にはナンセンスに見えるかもしれない質問:私は単にマルチスレッドを使用することができますが、何が用途ですか?私の意見では、この答えはさらにナンセンスです。いわゆる「何が真実かを知る」は、「真実が何があるかを知る」、「真実を知る」、「なぜ使用するのか」が「真実を知る」ことです。 「真実を知る」というレベルに到達することによってのみ、知識ポイントを自由に適用できると言えます。わかりました、この問題について私がどう思うか教えてください:
(1)マルチコアCPUの利点に完全なプレイをする
業界の進歩により、今日のラップトップ、デスクトップ、さらには商用アプリケーションサーバーはすべてデュアルコアであり、4コア、8コア、または16コアでさえ珍しいことではありません。シングルスレッドプログラムの場合、デュアルコアCPUで50%が無駄になり、75%が4コアCPUで無駄になります。シングルコアCPUのいわゆる「マルチスレッド」は、偽のマルチスレッドです。プロセッサは同時にロジックの一部のみを処理しますが、スレッドは比較的迅速に切り替わり、複数のスレッドが「同時に」実行されているように見えます。マルチコアCPUのマルチスレッドは、実際のマルチスレッドです。マルチセグメントロジックが同時に動作し、マルチスレッドが機能する可能性があります。それは、CPUを最大限に活用するという目標を達成するために、マルチコアCPUの利点に完全に完全なプレイを与えることができます。
(2)詰まりを防ぎます
プログラムの運用効率の観点から見ると、シングルコアCPUはマルチスレッドの利点に完全なプレーを提供するだけでなく、シングルコアCPUでマルチスレッドを実行するとスレッドコンテキストの切り替えを引き起こすため、プログラムの全体的な効率を低下させます。これにより、プログラムの全体的な効率が低下します。ただし、閉塞を防ぐために、単一コアCPUにマルチスレッドを適用する必要があります。単一コアCPUが単一のスレッドを使用している場合、たとえば特定のデータをリモートで読み取る限り、ピアは長い間返さず、タイムアウト時間を設定していない場合、データが返される前にプログラム全体が実行されるのを停止します。マルチスレッドはこの問題を防ぐことができます。複数のスレッドが同時に実行されます。 1つのスレッドのコードがデータの読み取りをブロックされている場合でも、他のタスクの実行に影響しません。
(3)モデル化しやすい
これはそれほど明白ではない別の利点です。シングルスレッドプログラミング、シングルスレッドプログラミングの大きなタスクがあると仮定し、多くのことを考慮する必要があり、プログラムモデル全体を構築する方が面倒です。ただし、この大きなタスクAをいくつかの小さなタスク、タスクB、タスクC、およびタスクDに分割し、プログラムモデルを個別に構築し、これらのタスクを複数のスレッドで個別に実行すると、はるかに簡単になります。
2。スレッドの作成方法
より一般的な問題は、一般的に2つです。
(1)スレッドクラスを継承します
(2)実行可能なインターフェイスを実装します
どちらが優れているかについては、インターフェイスを実装する方法は継承クラスメソッドよりも柔軟であり、プログラム間の結合を減らすことができるため、後者が間違いなく優れていることは言うまでもありません。インターフェイス指向のプログラミングは、設計パターンの6つの主要な原則の中核でもあります。
3. start()メソッドとrun()メソッドの違い
start()メソッドが呼び出された場合にのみ、マルチスレッドの特性が表示され、異なるスレッドのrun()メソッドのコードが交互に実行されます。 run()メソッドを呼び出すだけの場合、コードは同期して実行されます。別のスレッドがrun()メソッドでコードを実行する前に、1つのスレッドのrun()メソッドのコードが実行されるのを待つ必要があります。
4.実行可能なインターフェイスと呼び出し可能なインターフェイスの違い
少し深い質問があり、Javaプログラマーが学んだ知識の幅も示しています。
実行可能なインターフェイスのrun()メソッドの返信値は無効であり、それが行うのは、run()メソッドでコードを実行することだけです。呼び出し可能なインターフェイスのcall()メソッドには、一般的な返品値があり、将来およびFutureTaskと併せて非同期実行の結果を取得するために使用できます。
これは実際には非常に便利な機能です。なぜなら、マルチスレッドが単一のスレッドよりも困難で複雑であるという主な理由は、マルチスレッドが未知のものでいっぱいであるためです。特定のスレッドは実行されましたか?スレッドはどのくらい実行されていますか?スレッドが実行されたときに予想されるデータはありますか?私たちにできることは、このマルチスレッドタスクが実行されるのを待つことだけではありません。 Callable+Future/FutureTaskは、マルチスレッドランニングの結果を取得でき、待機時間が長すぎて必要なデータが取得されないときにスレッドのタスクをキャンセルできます。それは本当に便利です。
5.サイクリックバリアとカウントダウンラッチの違い
少し似ているように見える両方のクラスは、コードがjava.util.concurrentの下で特定のポイントで実行されることを示すために使用できます。 2つの違いは次のとおりです。
(1)特定の時点でcyclicbarrierのスレッドが実行された後、スレッドは実行されなくなります。すべてのスレッドがこのポイントに到達するまで、すべてのスレッドは再び実行されません。 CountDownLatchはそうではありません。スレッドが特定の時点で実行された後、特定の値-1を与えるだけで、スレッドは実行され続けます。
(2)Cyclicbarrierは1つのタスクのみを呼び起こすことができ、CountDownLatchは複数のタスクを呼び起こすことができます
(3)Cyclicbarrierを再利用でき、CountDownLatchを再利用できず、カウント値は再利用されず、CountDownLatchは再び使用されません
6.揮発性キーワードの役割
非常に重要な問題は、マルチスレッドを学習して適用するすべてのJavaプログラマーがそれを習得する必要があることです。揮発性キーワードの役割を理解するための前提条件は、Javaメモリモデルを理解することです。ここではJavaメモリモデルについては話しません。ポイント31を参照できます。揮発性キーワードには2つの主要な関数があります。
(1)マルチスレッドは、主に視界と原子性の2つの特性を中心に展開します。揮発性キーワードによって変更された変数は、複数のスレッド間の可視性、つまり揮発性変数が読み取られるたびに最新のデータでなければなりません。
(2)基礎となるコードの実行は、私たちが見る高レベルの言語であるJavaプログラムほど単純ではありません。その実行は、javaコード - > bytecode-> bytecode-> c/c ++コードに従って対応するc/c ++コードを実行します - >ハードウェア回路との対話>現実には、パフォーマンスを向上させるために、JVMは指示を再注文する可能性があり、マルチスレッドの下で予期しない問題が発生する可能性があります。揮発性を使用すると、セマンティックな並べ替えが禁止され、もちろんコード実行の効率がある程度減少します
実用的な観点から、揮発性の重要な役割は、CASと組み合わせて原子性を確保することです。詳細については、AtomicIntegerなどのjava.util.concurrent.atomicパッケージの下のクラスを参照できます。
7。スレッドの安全とは何ですか
別の理論的な質問には、多くの答えがあります。私が個人的に最良の説明だと思うものを与えたいと思います。マルチスレッドとシングルスレッドで実行されたときにコードが常に同じ結果を得ることができる場合、コードはスレッドセーフです。
この問題について言及する価値があります。つまり、スレッドの安全性にはいくつかのレベルがあります。
(1)不変
文字列、整数、長いなどのように、それらはすべて最終タイプです。スレッドは値を変更できません。それらを変更したい場合は、新しいものを作成しません。したがって、これらの不変のオブジェクトは、同期手段なしでマルチスレッド環境で直接使用できます。
(2)絶対的な糸の安全性
ランタイム環境に関係なく、発信者は追加の同期測定を必要としません。これを行うには、通常、多くの追加費用を支払う必要があります。 Javaでは、実際にはスレッドセーフクラスではありません。ただし、copyonwritearraylistやcopyonwritearraysetなど、絶対にスレッドセーフのクラスもあります。
(3)相対的な糸の安全性
相対的な糸の安全性は、私たちが通常スレッドの安全と呼ぶものです。たとえば、ベクトル、追加および削除メソッドは原子操作であり、中断されませんが、これに限定されます。特定のベクトルを通過するスレッドが同時にスレッドが追加されると、障害のあるメカニズムである症例の99%で同時型変更のエクセプトが発生します。
(4)スレッドは安全ではありません
これについて何も言うことはありません。 ArrayList、LinkedList、Hashmapなどは、すべてスレッドクラスです。
8。Javaでスレッドダンプファイルを取得する方法
デッドループ、デッドロック、ブロック、ページの開口部の開口部の遅いなどの問題の場合、スレッドダンプを押すことは、問題を解決するための最良の方法です。いわゆるスレッドダンプは、スレッドスタックです。スレッドスタックを取得するための2つの手順があります。
(1)スレッドのPIDを取得すると、JPSコマンドを使用できます。また、PS -EF |を使用することもできます。 Linux環境のGrep Java
(2)スレッドスタックを印刷すると、JSTack PIDコマンドを使用できます。また、Linux環境でKill -3 PIDを使用することもできます。
また、スレッドクラスには、スレッドスタックを取得するためにも使用できるgetStackTrace()メソッドが提供されます。これはインスタンスメソッドであるため、この方法は特定のスレッドインスタンスにバインドされています。現在、特定のスレッドでスタックを実行するたびに。
9.スレッドにランタイム例外がある場合はどうなりますか?
この例外がキャッチされていない場合、スレッドは実行を停止します。別の重要なポイントは、このスレッドが特定のオブジェクトのモニターを保持している場合、オブジェクトモニターはすぐにリリースされます
10。2つのスレッド間でデータを共有する方法
スレッド間でオブジェクトを共有するだけで、wait/notify/notifyallを呼び起こして待ちます。たとえば、ブロックキューブロッキングキューは、スレッド間でデータを共有するために設計されています。
11。睡眠方法と待機方法の違いは何ですか
この質問は頻繁に行われます。睡眠方法と待機方法の両方を使用して、一定期間CPUを放棄できます。違いは、スレッドがオブジェクトのモニターを保持している場合、睡眠方法はこのオブジェクトのモニターを放棄せず、待機方法がこのオブジェクトのモニターを放棄することです。
12。プロデューサーの消費者モデルの役割は何ですか?
この質問は理論的ですが、重要です:
(1)生産者と消費者の消費能力の生産能力のバランスをとることにより、システム全体の運用効率を改善します。これは、生産者消費者モデルの最も重要な役割です。
(2)デカップリング、これは生産者と消費者モデルを伴う関数です。デカップリングとは、生産者と消費者の間にはより少ない接続があることを意味します。接続が少ないほど、相互の制約を受けずに独自に開発できるようになります。
13。threadlocalの使用は何ですか
簡単に言えば、threadlocalは時間のために空間を交換する慣行です。各スレッドは、データを分離し、データを共有しないためにオープンアドレスメソッドによって実装されたthreadlocal.threadlocalMapを維持しているため、スレッドの安全性の問題はありません。
14.なぜwait()とnotify()/notifyall()メソッドを同期ブロックで呼び出すのか
これはJDKによって強制されています。 wait()メソッドとnotify()/notifyall()メソッドは、呼び出す前に最初にオブジェクトのロックを取得する必要があります
15。オブジェクトモニターを放棄するときのwait()メソッドとnotify()/notifyall()メソッドの違いは何ですか
wait()メソッドとnotify()/notifyall()メソッドの違いは、オブジェクトモニターをあきらめるときに、wait()メソッドがすぐにオブジェクトモニターを解放し、notify()/notifyall()メソッドは、オブジェクトモニターをgivingする前にスレッドの残りのコードが実行されるのを待機します。
16.スレッドプールを使用する理由
スレッドの頻繁な作成と破壊を避けて、スレッドオブジェクトの再利用を実現してください。さらに、スレッドプールを使用すると、プロジェクトに応じて並行性の数も柔軟に制御できます。
17.スレッドがオブジェクトモニターを保持するかどうかを検出する方法
また、スレッドがオブジェクトモニターを保持するかどうかを判断する方法があることを知るために、インターネットでマルチスレッドインタビューの質問を見ました。スレッドクラスは、オブジェクトOBJのモニターがスレッドによって保持されている場合にのみtrueを返すHoldSlock(Object OBJ)メソッドを提供します。これは静的な方法であることに注意してください。つまり、「特定のスレッド」は現在のスレッドを指します。
18.同期とReentrantLockの違い
同期は、その場合と同じキーワードであり、その間、ReentrantLockはクラスです。これは2つの本質的な違いです。 ReentrantLockはクラスであるため、同期するよりもますます柔軟な機能を提供します。これは、継承され、方法を持ち、さまざまなクラス変数を持つことができます。同期よりもReentrantLockのスケーラビリティは、いくつかのポイントに反映されます。
(1)ReentrantLockはロックを取得するのに待ち時間を設定し、したがって、デッドロックを避けることができます
(2)ReentrantLockはさまざまなロック情報を取得できます
(3)ReentrantLockは、マルチチャネル通知を柔軟に実装できます
さらに、2つのロックメカニズムは実際には異なります。基礎となるReentrantLockは、UnsafeのParkメソッドをロックするように呼び出し、同期操作はオブジェクトヘッダーのマークワードになるはずです。これはわかりません。
19。同時の並行性は何ですか
並行ハッシュマップの並行性はセグメントのサイズであり、デフォルトでは16です。つまり、最大16個のスレッドは同時に同時に動作することができます。これは、ハッシュテーブルでのConcurrenthashmapの最大の利点でもあります。いずれにせよ、ハッシュテーブルには同時に2つのスレッドがハッシュテーブルでデータを取得できますか?
20。ReadWriteLockとは何ですか
まず第一に、ReentrantLockが良くないということではなく、ReentrantLockが時々制限されていることを明確にしましょう。 ReentrantLockを使用している場合、執筆データとスレッドBの読み取りデータによって引き起こされるデータの矛盾を防ぐことができます。ただし、このようにして、スレッドCの読み取りデータとスレッドDの読み取りデータもデータを読み取っている場合、データはデータを変更しません。ロックする必要はありませんが、それでもロックされているため、プログラムのパフォーマンスが低下します。
このため、Read-Write Lock ReadWritelockが生まれました。 readwritelockは、読み取りワイトロックインターフェイスです。 Reentrantreadwritelockは、読み取りと書き込みの分離を実現するReadWritelockインターフェイスの具体的な実装です。読み取りロックは共有され、書き込みロックは排他的です。読み、読み、読み取りは相互に排他的ではありません。読み取りと書き込み、書き込み、読み取り、書き込み、書き込みのみが相互に排他的であり、読み取りと書き込みのパフォーマンスを改善します。
21. FutureTaskとは何ですか
これは実際に前述のことです。 FutureTaskは、非同期操作タスクを表します。呼び出し可能な特定の実装クラスをFutureTaskに渡すことができます。これは、この非同期操作の結果が取得され、それが完了したかどうかを判断し、タスクをキャンセルするのを待つことができます。もちろん、FutureTaskは実行可能なインターフェイスの実装クラスでもあるため、FutureTaskもスレッドプールに配置できます。
22. Linux環境で最も長いCPUを使用するスレッドを見つける方法
これはより実用的な問題であり、この問題は非常に意味があると思います。あなたはこれを行うことができます:
(1)プロジェクトのPID、JPSまたはPS -EFを取得| Grep Java、前に言及されています
(2)TOP -H -P PID、注文は変更できません
これにより、現在のプロジェクトが各スレッドにかかるCPU時間の割合が印刷されます。ここの1つはLWPであり、オペレーティングシステムネイティブスレッドのスレッド番号であることに注意してください。私のノートブックMountainはLinux環境にJavaプロジェクトを展開していないため、スクリーンショットやデモンストレーションを取得する方法はありません。会社がLinux環境を使用してプロジェクトを展開している場合は、試すことができます。
「TOP -H -P PID」 +「JPS PID」を使用すると、高いCPUを占めるスレッドスタックを簡単に見つけることができ、それにより高いCPUの占有の理由を配置します。これは、一般にデッドループにつながる不適切なコード操作によるものです。
最後に、LWPは「TOP -H -P PID」で再生されたことが10進数であり、「JPS PID」で演奏されるローカルスレッド番号は16進数であることを言及させてください。変換後、高いCPUを占める現在のスレッドスタックを見つけることができます。
23。Javaプログラミングデッドロックを引き起こすプログラムを書く
私はこの質問を初めて見て、それが非常に良い質問だと思った。多くの人々は、デッドロックがどのようなものかを知っています。スレッドAとスレッドBは、お互いのロックが無限のデッドループをプログラムを継続させるのを待っています。もちろん、それはこれに限定されています。デッドロックプログラムの作成方法を尋ねると、わかりません。率直に言って、あなたはデッドロックが何であるかを理解していません。あなたが理論を理解しているなら、あなたは完了します。基本的に、実際にデッドロックの問題を見ることができません。
デッドロックとは何かを本当に理解するために、この質問は難しくありません。いくつかのステップがあります。
(1)2つのスレッドには、それぞれLock1とLock2の2つのオブジェクトオブジェクトがあります。これらの2つのロックは、同期コードブロックのロックとして機能します。
(2)スレッド1のrun()メソッドでは、同期コードブロックは最初にlock1、thread.sleep(xxx)のオブジェクトロックを取得します。時間はあまりかかりません。50ミリ秒はほぼ同じで、次にロック2のオブジェクトロックが取得されます。これは主に、スレッド1が2つのオブジェクトのオブジェクトロックを連続的に取得するのを防ぐために行われます:lock1とlock2。
(3)スレッド2の実行)(メソッドでは、同期コードブロックは最初にオブジェクトロック2を取得し、次にオブジェクトロック1を取得します。もちろん、オブジェクトロック1は既にスレッド1ロックで保持され、スレッド2はスレッド1を待機してオブジェクトロック1ロック1を解放する必要があります。
このようにして、スレッド1の「スリープ」とスレッド2がオブジェクトロック2を取得した後。スレッド1は、この時点でオブジェクトロック2を取得しようとし、ブロックされます。この時点で、デッドロックが形成されます。もうコードを書きません。多くのスペースを占有します。 Java Multithreading 7:Deadlockこの記事には、上記の手順のコード実装が含まれています。
24.ブロッキングスレッドを目覚める方法
wait()、sleep()、またはjoin()メソッドを呼び出すためにスレッドがブロックされると、reduredexceptionを投げることでスレッドを中断して目覚める可能性があります。スレッドがIOの閉塞に遭遇する場合、IOはオペレーティングシステムによって実装され、Javaコードがオペレーティングシステムに直接連絡できないため、無力です。
25.不変のオブジェクトは、マルチスレッドに役立ちます
上記の問題は、不変のオブジェクトがオブジェクトのメモリの可視性を保証し、コードの実行効率を向上させる不変のオブジェクトを読み取るための追加の同期は必要ないということです。
26。マルチスレッドコンテキストスイッチングとは何ですか
マルチスレッドコンテキストの切り替えとは、CPU制御を1つの実行スレッドから別のスレッドに切り替えるプロセスを指し、CPUの実行権が取得されるのを待っています。
27.タスクを送信するときにスレッドプールキューがいっぱいになった場合、現時点で何が起こるか
LinkedBlockingQueueを使用している場合、つまり、固定されていないキューを使用している場合、それは問題ではありません。 LinkedBlockingQueueはほとんど無限のキューと見なされ、タスクを無限に保存できるため、ブロッキングキューにタスクを追加して実行を待ち続けます。たとえば、ArrayBlockingQueueなど、Boundedキューを使用している場合、タスクは最初にArrayBlockingQueueに追加されます。 ArrayBlockingQueueがいっぱいの場合、RejectedExecutionHandlerは拒否ポリシーを使用して完全なタスクを処理し、デフォルトはAbortPolicyです。
28. Javaで使用されているスレッドスケジューリングアルゴリズムは何ですか?
先制スタイル。スレッドがCPUを使用した後、オペレーティングシステムは、スレッドの優先度、スレッド飢erなどのデータに基づいて合計優先度を計算し、次にスライスをスレッドに割り当てます。
29。スレッドの機能は何ですか。スリープ(0)
この質問は上記の質問に関連しており、私はすべて一緒です。 Javaは先制スレッドスケジューリングアルゴリズムを使用するため、スレッドがCPUコントロールを取得することが多いことがあります。比較的優先度の低いスレッドを許可するためにCPU制御を取得するために、Thread.Sleep(0)を使用して、オペレーティングシステムを手動でトリガーすることができます。これは、CPUコントロールのバランスをとる操作でもあります。
30。スピンとは
多くの同期コードは非常に単純なコードであり、実行時間は非常に高速です。スレッドブロッキングにはユーザー状態とカーネル状態の切り替えが含まれるため、この時点で待っているスレッドをロックすることは価値のない操作かもしれません。 Synchronizedのコードは非常に高速で実行されるため、ロックを待っているスレッドがブロックされるのではなく、同期の境界で忙しいループを行うこともできます。これはスピンです。複数のビジーループを実行し、ロックが取得されていないことを見つけてからブロックした場合、これはより良い戦略かもしれません。
31. Javaメモリモデルとは何ですか
Javaメモリモデルは、Javaメモリへのマルチスレッドアクセスの仕様を定義します。 Javaメモリモデルを完全に説明する必要がありますが、ここではいくつかの文章では明確に説明することはできません。簡単に要約しましょう。
Javaメモリモデルのいくつかの部分:
(1)Javaメモリモデルは、メモリをメインメモリとワーキングメモリに分割します。クラスの状態、つまりクラス間で共有される変数は、メインメモリに保存されます。 Javaスレッドがメインメモリでこれらの変数を使用するたびに、メインメモリの変数を読み取り、独自の作業メモリに存在させます。独自のスレッドコードを実行するとき、これらの変数を使用し、独自のワーキングメモリで動作します。スレッドコードが実行されると、最新の値がメインメモリに更新されます。
(2)メインメモリとワーキングメモリの変数を動作させるために、いくつかの原子操作が定義されています
(3)揮発性変数を使用するルールを定義します
(4)起こること、つまり、最初の発生の原理は、操作Aが最初に操作Bで発生する必要があるいくつかのルールを定義します。たとえば、同じスレッドの制御フローの前のコードは、コントロールフローの背後にあるコードで最初に発生する必要があります。特定のコードがすべてのルールに準拠していない場合、その前に行われた場合、このコードはスレッドではなく安全でなければなりません。
32。CASとは何ですか
CAS、フルネームの比較とセットは、比較セットです。 3つのオペランドがあるとします:メモリ値V、古い期待値A、変更する値B。期待値aとメモリ値vが同じである場合にのみ、メモリ値はbに変更されて真の返されます。そうしないと、何も行われず、falseは返されます。もちろん、CASは、毎回取得された変数がメインメモリの最新値であることを確認するために、揮発性変数と協力する必要があります。それ以外の場合、古い期待値aは常にスレッドでは変更されない値です。特定のCAS操作が失敗する限り、成功することはありません。
33。楽観的なロックと悲観的なロックとは何ですか
(1)楽観的なロック:その名前と同様に、同時操作によって引き起こされるスレッドの安全性の問題について楽観的です。楽観的ロックは、競争が常に発生するとは限らないため、ロックを保持する必要はなく、比較する必要はありません。これらの2つのアクションをアトミック操作として設定して、メモリ内の変数を変更しようとします。それが失敗した場合、それは競合が発生することを意味し、その後、対応する再試行ロジックがあるはずです。
(2)悲観的なロック:その名前と同様に、それは同時操作によって引き起こされる糸の安全性の問題について悲観的です。悲観的なロックは、競争が常に発生すると考えています。したがって、リソースが操作されるたびに、直接ロックされているかどうかに関係なく、同期するように排他的ロックを保持し、リソースが操作されます。
34。AQとは何ですか
AQについて簡単に話しましょう。 AQSのフルネームは、抽象化された精神性です。翻訳すると、抽象キューシンクロナイザーである必要があります。
java.util.concurrentの基礎がCASである場合、AQSはJava Concurrencyパッケージ全体の中核であり、ReentrantLock、CountDownLatch、Semaphoreなどがすべて使用します。 AQSは、実際にはすべてのエントリを双方向のキューの形で接続します。たとえば、ReentrantLock。すべての待機スレッドはエントリに配置され、双方向のキューに接続されています。前のスレッドがReentrantLockを使用する場合、双方向キューの最初のエントリが実際に実行を開始します。
AQSは、双方向のキューに関するすべての操作を定義しますが、開発者が使用するTryLockおよびTryReleaseメソッドのみを開きます。開発者は、独自の実装に従ってTryLockおよびTryReleaseメソッドを書き換えて、独自の並行機能関数を実装できます。
35。シングルトンモードのスレッド安全
決まり文句の問題、最初に言うことは、シングルトンパターンのスレッドの安全性が次のことを意味するということです。特定のクラスのインスタンスは、マルチスレッド環境で1回のみ作成されることです。シングルトンパターンを書く方法はたくさんあります。まとめてみましょう。
(1)空腹の男のシングルトンパターンを書く:糸の安全
(2)怠zyなシングルトンパターンを書く:非read-Safe
(3)ダブルチェックロックのシングルトンモードを書く:スレッドの安全
36。セマフォの機能は何ですか
セマフォはセマフォであり、その機能は特定のコードブロックの並行性の数を制限することです。 Semaphoreには、integer nを通過できるコンストラクターがあり、Nスレッドのみが特定のコードにアクセスできることを示しています。 nを超えた場合は、スレッドがコードブロックを完了し、次のスレッドを入力するまで待ってください。このことから、セマフォコンストラクターで通過した整数n = 1が同期になるのと同等であることがわかります。
37。ハッシュテーブルのsize()メソッドに「return count」というステートメントが1つだけあるので、なぜまだ同期する必要があるのですか?
これは私が以前に持っていた混乱であり、あなたがこの質問について考えたことがあるのだろうか。メソッドに複数のステートメントがあり、それらがすべて同じクラス変数を動作している場合、マルチスレッド環境にロックを追加しない場合、必然的にスレッドの安全性の問題を引き起こします。これは理解しやすいですが、Size()メソッドには明らかに1つのステートメントしかないので、なぜロックを追加する必要があるのですか?
この問題に関して、私はそれをゆっくりと勉強することでそれを理解しました、そして、2つの主な理由があります:
(1)固定クラスの同期方法を同時に実行できるスレッドは1つだけですが、クラスの非同期方法では、複数のスレッドが同時にアクセスできます。だから、問題があります。たぶん、スレッドAはハッシュテーブルのプット方法を実行するときにデータを追加している可能性があり、スレッドBは通常、ハッシュテーブルの現在の要素の数を読み取るためにsize()メソッドを呼び出すことができます。読み取り値は最新ではないかもしれません。スレッドAがデータを追加したかもしれませんが、サイズ++なしでは、スレッドBはすでにサイズを読み取っています。したがって、スレッドBの場合、読み取りサイズは不正確でなければなりません。 Size()メソッドに同期を追加した後、スレッドAがプットメソッドを呼び出す後にのみスレッドBがSize()メソッドを呼び出すことを意味します。
(2)CPUはコードを実行しますが、Javaコードではありません。これは非常に重要であり、覚えておく必要があります。 Javaコードは最終的に実行のためにアセンブリコードに翻訳され、アセンブリコードはハードウェアサーキットと真に相互作用できるコードです。 Javaコードの1行しかないことがわかったとしても、Javaコードがコンパイルされていることがわかったとしても、生成されたバイトコードの行は1つしかありません。基礎となるレイヤーの場合、このステートメントには1つの操作しかないという意味ではありません。 「return count」という文は、実行するために3つのアセンブリステートメントに翻訳されていると仮定しており、最初の文が実行された後にスレッドが切り替わる可能性があります。
38。どのスレッドがスレッドクラスのコンストラクターであり、どのスレッドで呼び出される静的ブロックが
これは非常にトリッキーでunningな質問です。覚えておいてください:スレッドクラスのコンストラクターと静的ブロックは、新しいスレッドクラスが配置されているスレッドで呼び出され、実行中のコードはスレッド自体によって呼び出されます。
上記のステートメントがあなたを混乱させている場合は、例を挙げてみましょう。新しいthread1がthread2にあり、新しいthread2がメイン関数にあると仮定します。
(1)thread2のコンストラクターと静的ブロックはメインスレッドによって呼び出され、thread2のrun()メソッドはthread2自体によって呼び出されます
(2)thread1のコンストラクターと静的ブロックはthread2で呼び出され、thread1のrun()メソッドはthread1自体によって呼び出されます
39。同期方法と同期ブロックの間のより良い選択はどれですか?
同期するブロックを同期します。つまり、同期ブロックの外側のコードは非同期に実行されるため、メソッド全体を同期するよりもコードの効率が向上します。 1つの原則を知ってください:より少ない同期範囲
より良い。
この記事では、同期の範囲が小さいほど良いが、Java仮想マシンにはロックの粗さと呼ばれる最適化方法があり、同期範囲を増やすことになることに言及したいと思います。これは便利です。たとえば、StringBufferはスレッドセーフクラスです。当然、最も一般的に使用されるappend()メソッドは同期方法です。コードを書くとき、文字列を繰り返し追加します。つまり、繰り返しロックされていることを意味します - >ロック解除はパフォーマンスに適していません。これは、Java仮想マシンがこのスレッドでカーネル状態とユーザー状態を繰り返し切り替える必要があることを意味するためです。したがって、Java仮想マシンは、複数の追加メソッドで呼び出されたコードでロックコース操作を実行し、複数の追加操作を追加メソッドのヘッドとテールに拡張し、大きな同期ブロックに変換します。これにより、ロックの数が減少します - >ロック解除時間、コード実行の効率を効果的に改善します。
40.高い並行性と短いタスク実行時間を持つ企業にスレッドプールを使用する方法は?並行性が低く、タスクの実行時間が長い企業にスレッドプールを使用する方法は?並行性と長いサービス実行時間を持つ企業にスレッドプールを使用する方法は?
これは、同時プログラミングのWebサイトで見た質問です。この質問を最後に言って、誰もがそれを見て考えることができることを願っています。この問題に関して、私の個人的な意見は次のとおりです。
(1)高い並行性と短いタスク実行時間、スレッドプールスレッドの数をCPUコア番号+1に設定して、スレッドコンテキストの切り替えを減らすことができます
(2)并发不高、任务执行时间长的业务要区分开看:
a)假如是业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有的CPU闲下来,可以加大线程池中的线程数目,让CPU处理更多的业务
b)假如是业务时间长集中在计算操作上,也就是计算密集型任务,这个就没办法了,和(1)一样吧,线程池中的线程数设置得少一些,减少线程上下文的切换
(3)并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步,至于线程池的设置,设置参考(2)。最后,业务执行时间长的问题,也可能需要分析一下,看看能不能使用中间件对任务进行拆分和解耦。
Java线程阻塞(Blocked)的类型:
调用sleep函数进入睡眠状态,Thread.sleep(1000)或者TimeUnit.SECONDS.sleep(1),sleep不会释放锁。
等待(wait)某个事件,分为两种,(wait,notify,notifyAll),(await, signal,signalAll) ,后面会详细介绍。wait和await会释放锁,且必须在获取到锁的环境才能调用。
等待锁,synchronized和lock环境中,锁已经被别的线程拿走,等待获取锁。
IO阻塞(Blocked),比如网络等待,文件打开,控制台读取。System.in.read()。