まず、キャッシュライン(キャッシュライン)
CPUのキャッシュはキャッシュライン単位でキャッシュされており、複数のスレッドが異なる変数を変更し、これらの変数が同じキャッシュラインにある場合、お互いのパフォーマンスに影響を及ぼします。
キャッシュラインは通常64バイトで、メインメモリ内のアドレスのブロックを効果的に参照します。Javaのlong型は8バイトであるため、8つのlong型変数をキャッシュラインに格納できます。
2つ目は、キャッシュラインの充填
誤った共有を解決する最も簡単な方法はパディングです。たとえば、longは8バイトを占め、Javaオブジェクトヘッダーは32ビットシステムでは32ビット(4バイト)、64ビットシステムでは64ビットを占めます( 8バイト)。キャッシュラインは64バイトで、6つのlongを埋めることができます(1つのlongと6はlongを埋めるために使用され、合計:8 + 6 * 8 = 56バイト)。これは、64ビット仮想マシンで正確に64ワードを占めますセクションでは、32ビット仮想マシンの下にキャッシュラインが1つしかないため、複数のVolatileLongキャッシュラインを回避できます。
javaは、キャッシュライン全体を埋めるために、1つの長いフィールドと6つの長いフィールドを使用して、誤った共有を回避していることがわかります。
3つ、@ sun.misc.Contendedアノテーション
1. jdk8が@ sun.misc.Contendedの使用を開始しました。このアノテーションをフィールドに追加すると、フィールドが別のキャッシュライン(キャッシュライン)を占有して、誤った共有を回避できます。仮想マシンを起動するときに、-XX:-RestrictContendedパラメータを指定してください
2. jdk7の仮想マシンは不要なフィールドを最適化するため、7 longを使用してキャッシュラインを埋めることは不可能になります。jdk7の使用は避けてください
4番目に、仮想マシンオブジェクトのフィールドシーケンスが自動的に配置されます。
HotSpot JVMの場合、すべてのオブジェクトに2ワードのオブジェクトヘッダーがあります。最初のワードは、24ビットのハッシュコードと8ビットのフラグビット(ロックステータスやロックオブジェクトなど)で構成されるマークワードです。2番目の単語は、オブジェクトが属するクラスへの参照です。配列オブジェクトの場合は、配列の長さを格納するために追加のワードが必要です。各オブジェクトの開始アドレスは、パフォーマンスを向上させるために8バイトに揃えられます。したがって、オブジェクトをカプセル化する際の効率のために、オブジェクトフィールド宣言の順序は、バイトサイズに基づいて次の順序に並べ替えられます:
double(8)およびlong(8)
ints(4)およびfloat(4)
short(2)そして、chars(2)
booleans(1)およびbytes(1)
参照(4/8)
<サブクラスフィールドは上記の順序を繰り返します>
5、いくつかのスレッド共有パフォーマンスの比較
シングルスレッドロックフリー:1(シングルスレッドロックフリー条件のパフォーマンスに基づいて、遅くなります)
シングルスレッドロックロック:33
シングルスレッドcasロック:19
シングルスレッドvolatile:16
マルチスレッドロックロック:747
マルチスレッドcasロック:100