アトミックアトミック操作並行プログラミング操作] [Javaの] [Javaで並行プログラミング

抜粋:https://www.cnblogs.com/54chensongxia/p/11910681.html

Javaで] [アトミック操作並行プログラミング

 

アトミック何である

アトミック操作が細分化されていない1つ以上の操作を指します。これらの操作を中断することができない順序は、これらのステップは、(無停止)のみカット部を行わなくてもよいです。列子の場合:

コピー
//就是一个原子操作
int i = 1;

//非原子操作,i++是一个多步操作,而且是可以被中断的。
//i++可以被分割成3步,第一步读取i的值,第二步计算i+1;第三部将最终值赋值给i i++;

アトミック操作のJava

Javaでは、我々は、同期ロックやアトミックCASの操作により作動を実現することができます。

CASの動作

比較およびスワップCASが参照され、この動作は、アトミック動作を保証するために、ハードウェア・レベルでハードウェアレベルの操作です。CASは、メモリ値V、旧Aの期待値は、新しい値Bを変更する、3つのオペランドを持っています AとVの期待値が同じメモリ値である場合のみと、メモリ値VはBに改訂された場合、または何もしません。Javaではsun.misc.Unsafeクラスを提供compareAndSwapIntし、compareAndSwapLongCASを達成するためにいくつかの方法を。

さらに、以下の原子JDKパッケージに以下に示す原子CAS実装に基づいて多くのクラスを提供します。

ここでは、それらを使用しAtomicInteger、これらのクラスにアトミック操作を使用する方法を見てします。

コピー
package com.csx.demo.spring.boot.concurrent.atomic;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerDemo { private static int THREAD_COUNT = 100; public static void main(String[] args) throws InterruptedException { NormalCounter normalCounter = new NormalCounter("normalCounter",0); SafeCounter safeCounter = new SafeCounter("safeCounter",0); List<Thread> threadList = new ArrayList<>(); for (int i = 0; i < THREAD_COUNT ; i++) { Thread thread = new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 10000; j++) { normalCounter.add(1); safeCounter.add(1); } } }); threadList.add(thread); } for (Thread thread : threadList) { thread.start(); } for (Thread thread : threadList) { thread.join(); } System.out.println("normalCounter:"+normalCounter.getCount()); System.out.println("safeCounter:"+safeCounter.getCount()); } public static class NormalCounter{ private String name; private Integer count; public NormalCounter(String name, Integer count) { this.name = name; this.count = count; } public void add(int delta){ this.count = count+delta; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getCount() { return count; } public void setCount(Integer count) { this.count = count; } } public static class SafeCounter{ private String name; private AtomicInteger count; public SafeCounter(String name, Integer count) { this.name = name; this.count = new AtomicInteger(count); } public void add(int delta){ count.addAndGet(delta); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getCount() { return count.get(); } public void setCount(Integer count) { this.count.set(count); } } }

上記のコードは、我々は、カウンタと、カウンタ共通アトミック操作(のAtomicIntegerカウント使用して)作成しています。その後、100個のスレッドを作成、それぞれがカウントする1万回を行いました。理論的に実行した後、スレッド、カウンタ値は1,000,000ですが、結果は以下の通りであります:

コピー
normalCounter:496527
safeCounter:1000000

各実行は、共通カウンタの値は、すべてのAtomicInteger 1,000,000をカウントするカウンタを使用して、同じではありません。

CASの動作上の問題

  • ABAの問題:値が変化しない演算値の時にチェックするためにCASの必要性の下にあるため、更新が変更されていない場合、値がAであれば、しかし、Bになった、彼はAで、その後、CASのチェックを使用ときに、その値が変更されないことがわかりますが、実際に変更します。ソリューションABAの問題は、バージョン番号を使用することです。バージョン番号は、変数の前に追加され、各変数は場合バージョン番号と1つの更新され、その後、A-B-Aは、図1A-2B-3Aなります。

JDK原子Java1.5パッケージの先頭からABAの問題に対処するために、クラスのAtomicStampedReferenceを提供します。このクラスの動作方法は、現在の基準が予想参照に等しく、全てがアトミック基準値に等しくなるとフラグが指定された更新値に設定されている場合、現在のマークが、予想されるフラグに等しいのcompareAndSetチェックです。

  • 頭上に大きな長いサイクルタイム:失敗した長い時間のためのスピンCASの場合は、非常に大きなCPUの実行コストをもたらすでしょう。いくつかの効率改善が存在することになるので、JVMは、プロセッサによって提供される一時停止命令をサポートできる場合、一時停止コマンドは2つの目的があり、最初に、命令(デパイプライン)のパイプライン実行を遅らせることができる、CPUは、実装のためにあまりにも多くのリソースを消費しません、遅延時間の実装に依存し、プロセッサの数の遅延時間はゼロです。CPUのパイプラインによって引き起こされるメモリ競合(メモリ順序違反)の順序はCPUの効率を向上させるために、(CPUのパイプラインフラッシュを)がクリアされたときには、第2の出口ループを回避することができます。

  • 共有アトミック操作は専用の変数を保証することができます:共有変数に対して操作を実行するとき、我々はアトミック操作を保証するために、CASサイクル・アプローチを使用することができますが、サイクルCASを操作する複数の共有変数がアトミック動作を保証できない場合、あなたがロックを使用するか、トリッキーな方法を持つことができ、この時間は、それが動作するには、共有変数に複数の共有変数をマージすることです。例えば、I 2、J = IJ = 2Aで、マージ=、およびCASのIJで動作する2つの共有変数があります。AtomicReferenceは、オブジェクト間の参照原子を確保するために提供開始Java1.5 JDKのクラスからは、CASの操作に複数の変数にオブジェクトを置くことができます行われます。

使用すると、そのアトミック操作を保証するために、ロック

以上列子の欄には、我々は唯一のカウント方法上のライン上の共通カウンタロックを必要とします:

コピー
public synchronized void  add(int delta){ this.count = count+delta; }

次のように実行結果は以下のとおりです。

コピー
normalCounter:1000000
safeCounter:1000000

二つのカウンターは、正しい結果を得ることができます

CPUは、原子操作を達成する方法である#を

著者:コード男性の木材を書きます

出典:https://www.cnblogs.com/54chensongxia/p/11910681.html

著作権:このサイトの使い方「4.0 BY CCクリエイティブ・コモンズの合意」が明確に著者とソースの位置を示す記事で再現しました。

 
カテゴリー: 並行プログラミング

アトミック何である

アトミック操作が細分化されていない1つ以上の操作を指します。これらの操作を中断することができない順序は、これらのステップは、(無停止)のみカット部を行わなくてもよいです。列子の場合:

コピー
//就是一个原子操作
int i = 1;

//非原子操作,i++是一个多步操作,而且是可以被中断的。
//i++可以被分割成3步,第一步读取i的值,第二步计算i+1;第三部将最终值赋值给i i++;

アトミック操作のJava

Javaでは、我々は、同期ロックやアトミックCASの操作により作動を実現することができます。

CASの動作

比較およびスワップCASが参照され、この動作は、アトミック動作を保証するために、ハードウェア・レベルでハードウェアレベルの操作です。CASは、メモリ値V、旧Aの期待値は、新しい値Bを変更する、3つのオペランドを持っています AとVの期待値が同じメモリ値である場合のみと、メモリ値VはBに改訂された場合、または何もしません。Javaではsun.misc.Unsafeクラスを提供compareAndSwapIntし、compareAndSwapLongCASを達成するためにいくつかの方法を。

さらに、以下の原子JDKパッケージに以下に示す原子CAS実装に基づいて多くのクラスを提供します。

ここでは、それらを使用しAtomicInteger、これらのクラスにアトミック操作を使用する方法を見てします。

コピー
package com.csx.demo.spring.boot.concurrent.atomic;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerDemo { private static int THREAD_COUNT = 100; public static void main(String[] args) throws InterruptedException { NormalCounter normalCounter = new NormalCounter("normalCounter",0); SafeCounter safeCounter = new SafeCounter("safeCounter",0); List<Thread> threadList = new ArrayList<>(); for (int i = 0; i < THREAD_COUNT ; i++) { Thread thread = new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 10000; j++) { normalCounter.add(1); safeCounter.add(1); } } }); threadList.add(thread); } for (Thread thread : threadList) { thread.start(); } for (Thread thread : threadList) { thread.join(); } System.out.println("normalCounter:"+normalCounter.getCount()); System.out.println("safeCounter:"+safeCounter.getCount()); } public static class NormalCounter{ private String name; private Integer count; public NormalCounter(String name, Integer count) { this.name = name; this.count = count; } public void add(int delta){ this.count = count+delta; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getCount() { return count; } public void setCount(Integer count) { this.count = count; } } public static class SafeCounter{ private String name; private AtomicInteger count; public SafeCounter(String name, Integer count) { this.name = name; this.count = new AtomicInteger(count); } public void add(int delta){ count.addAndGet(delta); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getCount() { return count.get(); } public void setCount(Integer count) { this.count.set(count); } } }

上記のコードは、我々は、カウンタと、カウンタ共通アトミック操作(のAtomicIntegerカウント使用して)作成しています。その後、100個のスレッドを作成、それぞれがカウントする1万回を行いました。理論的に実行した後、スレッド、カウンタ値は1,000,000ですが、結果は以下の通りであります:

コピー
normalCounter:496527
safeCounter:1000000

各実行は、共通カウンタの値は、すべてのAtomicInteger 1,000,000をカウントするカウンタを使用して、同じではありません。

CASの動作上の問題

  • ABAの問題:値が変化しない演算値の時にチェックするためにCASの必要性の下にあるため、更新が変更されていない場合、値がAであれば、しかし、Bになった、彼はAで、その後、CASのチェックを使用ときに、その値が変更されないことがわかりますが、実際に変更します。ソリューションABAの問題は、バージョン番号を使用することです。バージョン番号は、変数の前に追加され、各変数は場合バージョン番号と1つの更新され、その後、A-B-Aは、図1A-2B-3Aなります。

JDK原子Java1.5パッケージの先頭からABAの問題に対処するために、クラスのAtomicStampedReferenceを提供します。このクラスの動作方法は、現在の基準が予想参照に等しく、全てがアトミック基準値に等しくなるとフラグが指定された更新値に設定されている場合、現在のマークが、予想されるフラグに等しいのcompareAndSetチェックです。

  • 頭上に大きな長いサイクルタイム:失敗した長い時間のためのスピンCASの場合は、非常に大きなCPUの実行コストをもたらすでしょう。いくつかの効率改善が存在することになるので、JVMは、プロセッサによって提供される一時停止命令をサポートできる場合、一時停止コマンドは2つの目的があり、最初に、命令(デパイプライン)のパイプライン実行を遅らせることができる、CPUは、実装のためにあまりにも多くのリソースを消費しません、遅延時間の実装に依存し、プロセッサの数の遅延時間はゼロです。CPUのパイプラインによって引き起こされるメモリ競合(メモリ順序違反)の順序はCPUの効率を向上させるために、(CPUのパイプラインフラッシュを)がクリアされたときには、第2の出口ループを回避することができます。

  • 共有アトミック操作は専用の変数を保証することができます:共有変数に対して操作を実行するとき、我々はアトミック操作を保証するために、CASサイクル・アプローチを使用することができますが、サイクルCASを操作する複数の共有変数がアトミック動作を保証できない場合、あなたがロックを使用するか、トリッキーな方法を持つことができ、この時間は、それが動作するには、共有変数に複数の共有変数をマージすることです。例えば、I 2、J = IJ = 2Aで、マージ=、およびCASのIJで動作する2つの共有変数があります。AtomicReferenceは、オブジェクト間の参照原子を確保するために提供開始Java1.5 JDKのクラスからは、CASの操作に複数の変数にオブジェクトを置くことができます行われます。

使用すると、そのアトミック操作を保証するために、ロック

以上列子の欄には、我々は唯一のカウント方法上のライン上の共通カウンタロックを必要とします:

コピー
public synchronized void  add(int delta){ this.count = count+delta; }

次のように実行結果は以下のとおりです。

コピー
normalCounter:1000000
safeCounter:1000000

二つのカウンターは、正しい結果を得ることができます

CPUは、原子操作を達成する方法である#を

おすすめ

転載: www.cnblogs.com/xichji/p/11925836.html