JVMの概要

第II章:Javaのメモリ領域およびメモリオーバーフロー例外:

2.1メモリマップ:

メモリマップ
ヒープおよびメソッド領域はスレッドで共有され、
仮想マシンのスタック、ネイティブメソッドスタック、プログラムカウンタは、スレッドプライベートである;
1。スレッド・カウンタ:、バイトコードを実行する現在のスレッドを指定するために使用される行数。マルチスレッドを交互に達成するために実行時間により切り替えJVMスレッド割り当てであるスレッドが切り替え時に、いつでも、プロセッサの各スレッドは、正しい位置スレッドを復元するために、命令を実行しますスレッドがお互いに影響を与えないことを保証するために、その各スレッドは、別のスレッドカウンターを持っている必要があります。
2。仮想マシンスタック:スレッドのライフサイクルが同期しているが、同時に実行される各方法は、ローカル変数テーブル、オペランドスタック、動的リンク、およびその他の情報入口方法、各メソッド呼び出しを記憶するためのスタックフレームを作成し、基本的なデータを含むローカル変数テーブル記憶関連ローカル変数、オブジェクト参照及びアドレスを返し、実行処理の完了は、スタックのスタックフレームをプッシュするプロセスです。
3。ネイティブメソッドは、スタック、基本的に同一の仮想マシンスタックが混乱概して、実行まとめスタック、唯一の違いは、仮想マシン・スタックであるJavaメソッドの実装で、ネイティブメソッドスタックネイティブメソッドを実行して、ローカル方法は、一般的に他の言語(Cで使用されています。 、C ++、又はアセンブリ言語など)は、ネイティブなハードウェアおよびオペレーティングシステムプログラムに基づいて書かれ、コンパイルされた
4。Javaヒープ:共有スレッド。すべてのオブジェクトは、ここにメモリを割り当てられ、ガベージコレクション(「GCヒープ」)のメインエリアです。主ストレージオブジェクトの例。それを拡大することができます。論理的に連続し、必ずしも物理的に連続していない
5。メソッド領域(常置領域):クラス情報(フィールド、メソッド、インターフェース)仮想マシンを格納するインスタントコンパイルされたコードデータと同様に、定数、静的変数にロードされ、必要が物理的に連続実行時定数プールエリアではないメソッド、クラスファイルの一部であります(リテラルおよび記号参照のコンパイラによって生成され、直接参照)定数プールは、クラスローディングの後にこの領域に配置されます。コンパイル時に生成された定数に加えて、だけでなく、動的生成、例えばインターンStringクラス()を可能にします。jdk6.0前に、文字列定数プールは、法の領域でした。Jdk7.0後、ヒープインチ
6。ダイレクト・メモリ:仮想マシンの一部が実行されていない、あなたが直接外部ヒープメモリにアクセスすることができます。OutOfMemoryErrorがあるだろうときに動的メモリを拡張することができない場合、JDK 1.4で新しいNIOクラスが導入され、それはネイティブ関数を使用することができますライブラリダイレクト外部メモリヒープ割り当て、これはJavaオブジェクトとして参照されるメモリDirectByteBufferヒープによって運営されています。これはかなりそれがヒープとスタックの外に前後にデータをコピーするためにメモリを回避し、いくつかのシナリオでは、パフォーマンスを向上させることができます。

2.2オブジェクトの作成および異常

1.オブジェクトを作成
、(コンストラクタを呼び出さずに)反射をクローン(コンストラクタを呼び出すことなく、クローン)、新しい新しいキーワード、直列化復元:いくつかの方法を。
新しいファースト- >シンボルの参照定数プールがあるかどうかを確認し、シンボルクラスがロードされているかどうかのチェックは、あまりにも意味し、クラスのロードを実行するのではなく、その後、メモリを割り当てるために開始します。
メモリ割り当て:ポインタの衝突(Javaのメモリきちんとした、圧縮されたガベージコレクタのシリアル、ParNewで仕上げ)、フリーリスト(絡み合っ空きメモリ、CMSを終え圧縮なし)を
作成した同期の問題のオブジェクトを解く:1のメモリ空間を割り当て異なる(バッファTlabを割り当てネイティブスレッド)に割り当てられたメモリ空間2.プロセス同期処理(CASが失敗時の再試行を伴います)

2.メモリ・レイアウト・オブジェクト:
1、オブジェクトヘッダ:ランタイム・データ・オブジェクト自体(ハッシュコード、GC世代年齢ロック状態フラグ)(タイプポインタ:メタデータへのポインタ)
2、インスタンスデータ:実際のオブジェクト有効な情報(様々なフィールド)が格納され、
図3に示すように、アライメントパディング:プレースホルダバイト完了。

3.アクセスオブジェクトの位置:
ヒープ上の操作特定のオブジェクト上のスタックへの参照データ型
の2つの方法で:

  1. オブジェクトが移動されたとき(すなわち、動くオブジェクトがガベージコレクションのメモリの統合であろう)、オブジェクトのインスタンスへのハンドルポインタ単にハンドル内のデータを変更し、スタック・リファレンス(参照)を変更する必要はない:ハンドル。直接のポインタを変更する必要があります。
  2. 直接ポインタ:速く、ポインタの少ない時間のオーバーヘッドが配置されているので。

4.OutOfMemoryError異常:
1.javaヒープ(ヒープ)オーバーフロー:あまりにも多くのオブジェクト。注コンセプト:メモリリーク:アプリケーション・プログラム・メモリ空間は、無駄に、解放することはできません。メモリ不足と:その使用のための十分なスペースがありません、
2 VMのスタックオーバーフローおよびネイティブメソッドは、スタック:
スタックの深さは、要求された最大許容深さ1以上です。:StackOverflowErrorが
スタックを展開し、十分なメモリ空間2には適用されません。:OutOfMemoryErrorが発生
3.方法および実行時定数プールオーバーフロー:
4.ローカル・ダイレクト・メモリ・オーバーフロー:

第3章:ガベージコレクタとメモリ割り当て戦略

1.条件が決定されたオブジェクトの回復:
1、参照カウントアルゴリズム:レコードにカウンタを追加します。1への参照があります。参考文献は、彼が死んだいつでも-1〜0に失敗します。しかし、我々は、相互のループ参照の問題を解決することはできません。
前記到達可能性分析アルゴリズム(主流):出発点としてオブジェクトを選択します。チェーンは、リーチは使用できませんGC根の対象ではありません。出発点を選択します。
GCルーツ選択:1.オブジェクト対象オブジェクトVMスタック(スケールにローカルスタックフレーム)ゾーン2の方法は、参照クラスの静的属性参照は3方法定常領域を引用したネイティブの4ネイティブメソッドスタックメソッドは、オブジェクトを参照しました。
参考文献4種類:
1。強い参照:オブジェクトは強い参照に関連付けられているが回復されることはありません。新しい方法を使用して新しいオブジェクトへの強い参照を作成します。
オブジェクトOBJ =新しい新しいオブジェクト();
2.ソフト参照:ソフト参照オブジェクトが関連付けられてのみメモリ不足の場合に回収されます。ソフト参照を作成するためにSoftReferenceクラスを使用します。
オブジェクトOBJ =新しい新しいオブジェクト();
SoftReference SoftReference新しい新しいSF =(OBJ);
OBJ = nullは; //するオブジェクトのみがソフト参照に関連付けられている
3弱参照:オブジェクトに関連付けられた弱参照が回収され、それはそれを言うことですそれらが発生する前にのみ、次のガベージコレクションまで生き延びます。弱参照を作成するために、弱い参照クラスを使用します。
オブジェクトOBJ =新しい新しいオブジェクト();
弱い参照新しい新しい弱い参照WF =(OBJ);
OBJ = NULL;
4.ファントム参照:ゴーストやファントム参照が引用としても、オブジェクトが参照された仮想プレゼンスを持っているかどうか、知られているが、あなたが参照することにより、仮想オブジェクトを取得することはできません、彼らの生存期間に影響を与えません。オブジェクトが回収されたときに通知を受け取るために、ターゲットシステムの唯一の目的のために仮想基準を設定します。PhantomReferenceは、仮想基準を作成するために使用します。
オブジェクトOBJ =新しい新しいオブジェクト();
PhantomReference PhantomReference新しい新しいPF =(OBJ、NULL);
OBJ = NULL;
回復プロセスゾーン(永久世代):廃定数(プール内の任意のオブジェクトなく一定ポイント)と無用クラス( 1クラスのすべてのインスタンスは、クラスのClassLoaderが3 java.lang.Classクラスオブジェクト)を任意の場所ではなく、反射型のアクセスで参照されていない回収される2負荷回収されてきました。

2.ガベージコレクションアルゴリズム(フォーカス):
1.マーク-スイープアルゴリズム:効率が別個のメモリチップの多数で、その結果、高いない
大面積エデンエリアの生存者に分け2.コピーアルゴリズム(新世代)。最初のエデンエリアと遺族リカバリ領域を使用する場合:別のピース遺族領域にライブオブジェクトをコピーします。8:次に比率をクリア1は、古い時代を見つけるために、割り当てを保証するのに十分ではありません。
3.マーククリーンアップアルゴリズム:マーク-仕上げ-クリア。すべての生存オブジェクトは、外側の境界を離れてクリアし、片側に移動します。
4.世代のコレクションのアルゴリズム:新世代:レプリケーションアルゴリズム歳:マーク-スイープやマーク-仕上げ
3.いくつかのガベージコレクタ:
シングルスレッドとマルチスレッド:ガベージコレクタを指し、シングルスレッドのみ1つのスレッドを使用します、複数のスレッドを使用して、マルチスレッド、
シリアルおよびパラレルシリアルガベージコレクションの実装では、ユーザプログラムを一時停止する必要があることを意味し、ユーザプログラムの実行、と交互そのガベージコレクタを意味し、パラレルガベージコレクタとユーザプログラムを指し同時に。CMSとG1、及び他のガベージコレクタに加えて、連続的に実行されます。
ここに画像を挿入説明
1.Serial:コレクターの新世代の下で、基本的な、デフォルトのクライアントモード
2.ParNew:コレクターの新世代のための選択のシリアルマルチスレッド、サーバモード。これら二つの唯一の最初を合わせて、CMSでき
3.Parallel清掃を:新生代;複製アルゴリズム。アテンション・スループット。
4.Serial旧:のシリアル古いバージョン:マーク- CMSバックアップ計画として、一般的にクライアントのために使用さ仕上げ、1、およびパラレルスカベンジ一致。
5.Parallel旧:パラレル清掃を古いのバージョン。-マークは、仕上げ
スイープ-マーク:6.CMSを。最短目標復旧時間を取得します。比較可能。特長:CPUリソースに敏感で、
我々は、フローティングごみ、スペースデブリの多くは、処理できない
最先端技術:7.G1を。特徴:パラレルと同時、世代収集、空間の統合、予測可能な一時停止、

4.メモリの割り当てと回復の戦略:
マイナーGC:(エデンとサバイバー領域を含む)若い世代のスペースはメモリ再利用する
主なGCを永久世代をクリーンアップします。
フルGC:全体のヒープ領域のクリーンアップ-若い世代と永久世代を含むを。条件:
スペースの1歳の不足。
2.世代永遠の命(jkd7)またはメタデータ空間(jkd8)欠損症。
3.System.gc()メソッドの呼び出し。
プロモーションは失敗したと並行モード故障時に4.CMS GCが発生し
、古い時代に昇格平均が古い残りのメモリ空間5.YoungGC年よりも大きい場合
、大きなオブジェクトに割り当てるための継続的必要性がある6.
グローバルJavaで一時停止:停止-世界は現象。グローバルな一時停止、すべてのJavaコードを停止し、ネイティブコードを実行することができるが、JVMと相互作用することができない
、ガベージコレクションプロセスで(例えば前記ならびにサバイバーサバイバー0における物体1との間のレプリケーションなど)オブジェクトの移動含むしばしばこれは、更新されているオブジェクト参照の必要性につながりました。更新参照の正確さを保証するためには、Javaが停止にグローバルなシステムにつながる、これは「ストップ・ワールド」と呼ばれ、他のすべてのスレッドが中断されます。ストップ-世界はシステムのパフォーマンスに影響を与える存在、原理はガベージコレクションが「ストップ・ワールド」の時間を最小限に抑えることです。
メモリ割り当て戦略:
エデン1.オブジェクトの優先順位の割り当て
を直接歳に2.ラージオブジェクト(非常に長い文字列や配列)
歳のオブジェクト(対象年齢カウンタ)の3長期生存が入ります
の年齢を決定するために4ダイナミックオブジェクトを
5スペース割り当て保証

第7章:VMクラスローディング機構
1.クラスのロード処理。
メモリ内のクラス:ロード検証準備、解析し、初期化、使用してアンインストールいくつかの太字の順序を決定します。それらの間に散在解決します。
時間をロードするとそこには明確な始まりではありませんが、初期設定時間が決定され、そこに一つであり、唯一持っていることを

  1. 新しい、読み取りまたはクラスの静的フィールドセットの例としては、静的メソッドを呼び出します。
  2. java.lang.reflectで。コールを反映しています。
  3. クラスが初期化されると、親クラスの最初のトリガの初期化。
  4. メインメインクラスを含む、JVMを起動すると、初期化。
  5. どのような対応するクラスを扱う動的言語が初期化されていない、
    次の三つはしません。
  6. サブカテゴリーで親クラスの静的フィールドを参照、サブカテゴリーは、初期化が発生することはありません。
    System.out.println(SubClass.value); //値フィールドは、スーパークラスを定義する
    クラスで参照配列定義2.このクラスは、初期化をトリガしません。このプロセスは、アレイタイプは、仮想マシンによって自動的に生成された配列型を初期化し、サブクラスはプロパティとメソッドの配列を含むオブジェクトから直接継承します。
    スーパークラス[] =新しい新しいSCAスーパークラス[10]は、
    コンパイル時に前記定数は、自然のクラス定数の定義への直接参照が存在しない、と呼ばれる一定のプールクラスに入金され、したがって、クラスに定義された初期化定数を誘発しないであろう。
    System.out.println(ConstClass.HELLOWORLD)。

1.負荷:1>クラスの完全修飾名で定義されたバイナリバイトストリームクラスを返します。メソッド領域ランタイム3>にバイトストリームデータ構造によって表される2>静的記憶構造は、クラスオブジェクトは、このクラスの各種データ入力領域にアクセスするための方法を生成します。
バイナリストリームを取得:
ZIPパッケージから1読むには、根拠のJAR、EAR、WAR形式になります。
2.ネットワークから取得し、最も典型的なアプリケーションは、アプレットです。
このような動的エージェント技術、バイトjava.lang.reflect.ProxyののプロキシクラスProxyGenerator.generateProxyClassバイナリストリームの使用3.計算および実行時間を生成します。
4.は、JSPによって生成され、対応するクラスのクラスファイルなどの他のファイルから生成されました。

  1. 検証:ファイル形式の検証、認証メタデータ(情報記載バイトコードセマンティック分析)、バイトコード検証(データ・フローと制御フロー解析プログラムが正当なセマンティクスであることを保証するために、論理的な、クラスメソッド意志ボディチェック解析)、シンボリック参照の検証
  2. 調製:クラス変数は、静的クラス変数を変更して、準備フェーズのためのメモリ領域を用いる方法メモリを割り当てるための初期値を設定しています。インスタンス変数は、オブジェクトをJavaヒープにオブジェクトとともにインスタンス化されるときに割り当てられる、この段階でメモリを割り当てないであろう。初期値は、例えば、以下のクラス変数の値が0の代わりに123に初期化され、一般的に0の値です。パブリックstatic int値= 123;クラス変数が一定であれば、それは式に従って初期化されますが、0の代わりに割り当てられます。public static final int値= 123。
  3. 分析:直接参照を交換するプロセスのための基準の記号定数プール。主に分析動作のため:クラスおよびインタフェース、フィールド、メソッド、クラス、インタフェース方法。
  4. 初期化:本当にJavaコードのクラスを実行し始めました。プロセス仮想マシンクラスのコンストラクタ()メソッド。
    ()順コンパイラの声明文のブロック合併のすべてのクラスと静的変数でコンパイラクラスの代入演算によって自動的に収集されたと判定されたソースファイル内の文によって収集され表示されます。特に注目すべきなのは、それはそれだけの後に割り当てることができますクラス変数で定義される前にのみアクセスすることができない、クラス変数を定義するには、静的ステートメントのブロックへのアクセスです。静的ステートメントは、インターフェイスブロックに使用できませんが、割り当てクラス変数が初期化され、したがって異なるインタフェースとクラスを(生成する)方法が依然として存在します。しかし、インターフェイス()メソッドを実装し、異なるインターフェイスとクラスは、親インターフェイス()メソッドを実行する必要はありません。親インターフェイスを使用してインターフェイスで定義された親変数が初期化されますときにのみ。さらに、インタフェースの実装クラスは、初期化時に実行同じ()インターフェース方式ではありません。
    複数のスレッドが同時にクラスを初期化する場合は、クラス()メソッドを確実にするために、仮想機会が正しく、マルチスレッド環境でロックと同期され、のみ、このクラス()メソッドの1回のスレッドの実行があるだろう、他のスレッドを待ってブロックされます、アクティブスレッドが実行されるまで()メソッドを終了します。時間のかかる操作は、クラス()メソッドである場合、それはブロックされた複数のスレッドを作成することができ、実際のプロセスのこの閉塞は非常に微妙です。

2.クラスローダ
1は、それはでロードする必要があるクラスローダとクラス自体は一緒にJava仮想マシンでその独自性を確立します。
分類:
1.クラスローダ:C ++で実装は、仮想マシン自体の一部である; \ビンJVMが下識別
2.拡張クラスローダ:\ビンの\ extディレクトリをロードする、またはシステム変数パスのjava.ext.dirs下ライブラリ
ローディング経路上に指定されたユーザ・クラス(クラスパス)ライブラリ:3.アプリケーションクラスローダ

親委任モデル:基底クラスが統一されるようにクラスローダが、一緒の関係に優先順位を持っているとして、親委任モデルローダーの3種類との関係を整理するには、それは、Javaクラスを作成します。
作業プロセスは:まず、クラスローダのクラスローダは、親クラスローダがない完全な試みがそれをロードすることができる唯一の親クラスローダに要求を転送します。
別のエスケープ解析:オブジェクトの動的スコープの分析では、スレッドは、他のメソッドにアクセスするか、任意のオブジェクトへの任意の手段によってできない場合。このオブジェクトを最適化することができます。
三つの特徴:スタック分布、同期の排除、スカラー置換。

章XII、Javaのメモリモデルとスレッド。
1.Javaメモリモデル:プログラムで定義された変数のアクセス規則
1.メインメモリ(データ部に対応するヒープ・オブジェクト・インスタンス):すべての変数は、メインメモリに記憶されている
2ワーキングメモリ(VMスタック部月メインメモリレプリカコピーに変数を使用して、スレッドにスレッドの作業メモリに格納されたアナログプロセッサのキャッシュの前)は、変数のスレッド(読み取り、割り当て)上のすべての操作は、作業用メモリである必要があります直接メインメモリ変数を読み書きません。異なるスレッドワーキングメモリ変数に互いに直接にアクセスすることはできません、スレッド間で渡される変数の値との間にメインメモリに完了するために必要とされている
2.メモリの間の相互作用:
ロック(ロック):メインメモリ内の変数の役割を、変数にスレッド排他状態として識別。
(アンロック)ロックを解除:メインメモリ変数の役割を、変数がロックされた状態で放出され、変数のリリースは他のスレッドをロックすることができた後。
読み取る(読み出す):その後の使用の負荷運転のためにメインメモリ変数、スレッドの作業メモリにメインメモリから変数の値に作用する
荷重(負荷):ワーキングメモリ変数の役割その読み出し動作変数の値のワーキングメモリコピーにメインメモリから取得した変数。
(使用)を使用する仮想遭遇バイトコード命令は、変数の値を必要なときはいつでも作業メモリ変数の役割は、可変ワーキングメモリ値は、実行エンジンに渡され、操作が実行されます。
可変作業メモリに割り当てられた値に、実行エンジンから受信されたメモリ変数作業の役割、この操作を実行するたびに、仮想遭遇変数代入のバイトコード命令:(割り当て)を割り当てます。
店舗(店舗):後続の書込み動作するようにワーキングメモリ変数の役割、ワークメモリの変数の値は、メインメモリに転送されます。
WRITE(書き込み):ワーキングメモリに格納する動作からメインメモリ変数に変数の値を伝達されるメインメモリ変数に作用します。
ルールを満たすオペレーティング:
読むとロード・ストアと書き込みが順次行われなければなりません。必ずしも連続的に実行
•読み、負荷許可しない、店1と操作だけで起こる書く
最近の操作が一つのスレッドを割り当てる•後は、ワーキングメモリ内の変数の変更は、メインメモリに同期させなければならないということ、それを破棄することはできません。
•スレッドが戻ってメインメモリにワーキングメモリからのデータを同期する(任意のアクションを割り当てないで発生)する理由はありません許可しないでください。
•新しい変数のみをメインメモリに生まれることができますが、ワーキングメモリに直接変数の初期化(負荷またはASSIGN)を使用することを許可されていません。可変使用およびストア動作の実装を割り当て、負荷動作の後に実行されなければならない前に、すなわち、です。
•ペアで表示される必要があり、そのロック、ロックやアンロックを操作するだけで一つのスレッドを許可すると同時に、変数
あなたは、この変数の値のワーキングメモリをクリアする実行エンジンの前に変数を使用する変数のロックの操作を実行した場合•あなたは負荷を再または操作変数を初期化し実行するための値に割り当てる必要があり
•変数は、以前ロック操作をロックされていない場合、ロック解除操作を実行するために許可されていないが、変数が別のスレッドによってロック解除するために許可されていません。
•変数の実行ロック解除操作の前に、変数が最初にメインメモリに同期(実行ストアおよび書き込み操作)する必要があります。
揮発性の特殊性:弱い同期メカニズム、可視性、disableコマンドの並べ替え。保証の原子ません。
ロング、ダブル、特別ルール:8バイト。除読者は、2つのステップを可能にします。レア。
原子性(ロック、アトミッククラス):操作が中断されていない、どちらかのすべてが成功するかでの感覚で、すべてが失敗した実行「のライブと死にます」。
可視性(揮発性、同期、最終):スレッドが共有変数を変更すると、他のスレッドがすぐにこの変更を認識することができます。
秩序(揮発性、同期化):このスレッドで表示した場合、すべての操作が順序付けられている、スレッド内の別のスレッドが、すべての操作が乱れている場合に観察。
第一の原則は、最初に発生;、パイプロックルール、プログラムシーケンスルール揮発性変数のルール、ルールのスレッドが開始されると、スレッドがルールを終了し、スレッドのルールを破る、物体側ルール、推移
変換の状態を:
ここに画像を挿入説明スレッドパッケージには、次の5つの状態が含まれています。

  1. 新しい状態(新規):スレッドオブジェクトが作成された後は、新しい状態に入りました。たとえば、スレッドのスレッド=新しいスレッド()。
  2. レディ状態(Runnableを):としても知られている「実行可能状態。」スレッドオブジェクトを作成した後、スレッドを開始するように、他のスレッドは、オブジェクトのstart()メソッドを呼び出します。例えば、thread.start()。いつでも即応の状態をスレッドはCPUスケジューリングによって実行することができます。
  3. 状態(ランニング)の実行:実行のための許可を得るためにCPUスレッドを。なお、スレッドが実行されているだけの状態に準備完了状態から入力することができます。
  4. 阻塞状态(Blocked) : 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
    (01) 等待阻塞 – 通过调用线程的wait()方法,让线程等待某工作的完成。
    (02) 同步阻塞 – 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
    (03) 其他阻塞 – 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
  5. 死亡状态(Dead) : 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

第十三章:线程安全和锁优化
线程安全的等级:
1. 不可变:final 修饰 string等不可变类。绝对线程安全。
2. 绝对线程安全:基本没有绝对的。
3. 相对线程安全:这就是我们一般说的线程安全。如:vector等。
4. 线程兼容;arraylist等,
5. 线程对立:无法在多线程中使用,
线程安全的实现方法:
1. 互斥同步(阻塞式同步)

  1. 同步指的是:多个线程并发访问共享数据时,保证共享数据在同一时刻只能被一个线程使用。
  2. 互斥指的是:同步的手段。如:临界区、互斥量和信号量。
  3. 最基本的同步互斥手段:synchronized关键字。
    a) 原理:synchronized关键字经过编译后,会在同步代码块前后分别形成monitorenter和monitorexit这两个字节码指令。
    b) 在执行monitorenter指令时,首先要尝试获取对象锁。若这个对象没被设定锁,或已经拥有了这个对象锁,把锁的计数器+1。
    c) 相应的执行monitorexit指令时,锁计数器-1,当为0时释放锁。
    d) 若获得对象失败则阻塞当前线程。
  4. 另一种手段:ReentrantLock来实现
    reentrantLock增加的新功能:
    a) 等待可中断:当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待。
    b) 公平锁:可以讲多个线程在等待同一个锁时,必须按照申请锁的时间顺序依次获得锁。
    c) 锁绑定多个条件:一个ReentranLock对象可以同时绑定多个Condition对象。
  5. 两种方式的比较:
    a) 在JDK1.6之前在多线程环境中synchronized的吞吐量下降的严重,但ReentranLock性能几乎不变。
    b) 在JDK1.6之后二者性能基本上持平。
    c) 应该优先考虑使用synchronized来同步。
    2. 非阻塞同步
    1,互斥同步属于一种悲观的并发策略。即总认为不去做同步措施就一定会出现问题,故无论共享数据是否真的会出现竞争,都要加锁。
    2,非线程阻塞:是基于冲突检测的乐观并发控制策略。即先操作,如果没有其它线程征用共享数据,则成功。如果共享数据有征用,采取补偿措施。(不断的重试,直到成功)
    3. 无同步方案
    如果方法中不涉及共享数据,那它自然无须任何同步措施去保证正确性。
    1)可重入代码
    可重入的代码都是线程安全的,但并非所有的线程安全的代码都是可重入的。
    2)线程本地保存

锁优化:
锁优化技术:适应性自旋、锁消除、锁粗化、轻量级锁和偏向锁。
1.适应性自旋
1.自旋锁:当两个或两个以上的线程同时并行执行,让后面请求锁的那个线程“稍等一下”,但不放弃处理器的执行时间,看看持有所的线程是否能很快释放锁。
2.缺点:自旋的线程只会白白消耗处理器资源,带来性能的浪费。故需要使等待时间有一定的限度
3.改进:等待时间要自适应。等待时间随着程序运行和性能监控信息的不断完善。

2.锁消除
1.锁消除:虚拟机及时编译器在运行时,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行消除。
2.判断依据:源于逃逸分析的数据支持。若堆上的所有数据都不会逃逸出去从而被其他线程访问到,那就可以吧它们当作栈上的数据看待。
3.粗粒化
1.上面出现的问题:如果一系列的连续操作都对同一个对象反复加锁和解锁,甚至加锁操作是出现在循环体中,那即使没有线程竞争,频繁地进行互斥同步操作也会导致不必要的性能损耗。
2.措施:如果虚拟机探测到有这样一串零碎的操作都对同一个对象加锁,【将会把加锁同步的范围扩展到整个操作序列外部】。
4.轻量级锁
1.加锁过程:
1)代码进入到同步代码块的时候,如果此同步对象没有被锁定,将会在当前线程的栈帧中建立一个名为锁记录(Lock Record)空间,用来存储对象目前的头数据。
2)将对象的头记录更新为指向Lock Record的指针。
a)更新成功:那么这个线程就拥有了该对象的锁
b)失败:检查对象的对象头是否指向当前线程的栈帧。
a)是:说明当前线程已经拥有这个对象的锁,直接进入同步块中执行。
b)否:说明这个锁对象已经被其他线程抢占。
3)如果两条以上线程征用同一个锁,那轻量级锁失效。
2.解锁过程:
1)若对象的对象头仍然指向现成的锁记录,则把对象当前的Mark Word和线程中副本替换回来。
A)成功:整个同步过程完成
b)が失敗しました:説明他のスレッドがロックを取得しようとし、それはロックを解除するために同時に中断されたスレッドを起動します。
偏ったロック
1.区別ロック・軽量:
軽量ロック:競争が存在しない場合には、同時使用ミューテックスを排除します。
偏ったロック:全体の同期での競争が存在しない場合には排除されています。
2.ロック手順:
1)ロックオブジェクトは、最初のスレッドがマークされた仮想マシンパッケージオブジェクトヘッダを取得している場合に「01」
2)ロックスレッドIDをマークにWordオブジェクトに記録され得ます。
A)成功:関連するスレッドに各シンクブロックをロックするロックバイアスを保持した後、任意の同期操作を実行することはできません。
3.ロック解除プロセス:
1)このロックモードバイアスを獲得しようとする他のスレッドが存在し終わりました。
2)ロックオブジェクトに応じて「01」または「00」に戻りロック状態に現在ある、バイアスを取り消します。
4.利点:同期手順のパフォーマンスを向上させるが、競合とします。

おすすめ

転載: blog.csdn.net/qq_41703795/article/details/89280905