アート同時Javaプログラミング(8)ロック意味記憶

よく知られ、クリティカルセクション、ミューテックスロックからの実行を可能にします。

ロック解除は - 事前発生関係が確立します

Java同期メカニズムの中で最も重要な並行プログラミング時にロック。クリティカル領域の実装に加えて、相互排他ロックだけでなく、ロック・スレッドの放出が同じロック・スレッドを取得するためのメッセージを送信することができます。

class MonitorExample {
    int a = 0;
    public synchronized void writer() {         1 
    a++;              2
    }                3
    public synchronized void reader() {      4 
        int i = a;               5 
    ……
    }                  6
}

仮定するスレッドA実行ライタ()メソッドは、Bは、リーダー()メソッドを実行したスレッド。
事前発生ルール、起こる-前に、このプロセスの関係含まれる3つのカテゴリに分類することができます。
(1)プログラム・シーケンス・ルール、1-2,2-起こる&前に起こる前に3; 5、5 4が前に前-happens-起こり6。
(2)モニターロックの規則に従って、3-前に起こる4。。
(3)に従って起こります-before推移は、2が起こる-前に5。
ここに画像を挿入説明
スレッドは、スレッドBに同じロックを取得後、直ちにBをスレッドに見えるようになり、ロックする前に、すべての可視の共有変数を解放します

ロック解除と意味記憶の獲得

スレッドがロック共有変数を解放すると、JMMがリフレッシュされ、メインメモリへのスレッドローカルメモリに対応することになります。
スレッドがロックを取得すると、JMMはローカルメモリに対応するスレッドがディアサートされます。だから、ロックモニタ共有変数によって保護されたコードのクリティカル領域は、メインメモリから読み出されなければならないこと。
ここに画像を挿入説明
ロックや揮発性書き込みのリリースと同じメモリのセマンティクス、ロック取得と揮発性の読み出しが同じメモリセマンティクスを持ちます

概要

(1)スレッドのロックを解除は、本質的に、発行されたスレッドA(共有変数からなるスレッドが変更された)次のメッセージが、スレッドのロック取得する
(2)スレッドBは、本質的に、ロックを取得しBは、メッセージ(行わ共有変数のロックを解除する前に、変更された)の前にスレッドがスレッドの問題であり、受け入れ
(3)スレッドがロックを解放し、その後、Bがロックを取得スレッド、プロセスは、本質的にメインスレッドAでありますメモリBは、スレッドにメッセージを送信します。

ロックは、意味記憶を達成します

class ReentrantLockExample {
    int a = 0;
    ReentrantLock lock = new ReentrantLock();
    public void writer() {
        lock.lock();                  获取锁
        try {
            a++;
        } finally {
            lock.unlock();            释放锁
        }
    }
    public void reader() {
        lock.lock();                  获取锁
        try {
            int i = a; 
            ……
        }finally {
            lock.unlock();            释放锁
        }
    }
}

ReentrantLockのでは、ロックを取得するためのロック()メソッドを呼び出して、ロックを解除するロック解除()メソッドを呼び出します。
ReentrantLockのJava実装は、フレーム同期AbstractQueuedSynchronizer(本明細書では単にAQSをいう)に依存しています。AQSはすぐに我々が表示され、同期状態を維持するために(状態にちなんで命名)は、揮発性の変数の整数を使用して、これは重要な変数揮発性メモリReentrantLockのセマンティック実装です。
ここに画像を挿入説明
株式および非エクイティ・ロックへのReentrantLockのロック
公正なロックを使用して、ロック法ロック()は以下のトラックを呼び出します。

1)ReentrantLock:lock()2)FairSync:lock()3)AbstractQueuedSynchronizer:acquire(int arg)4)ReentrantLock:tryAcquire(int acquires)

ステップ4では、実際にロックを始めました


 protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState(); 获取锁的开始,首先会读volatile变量state
            if (c == 0) {
            	如果state=0且队列不为空,有线程正在获取锁。
                if (!hasQueuedPredecessors() &&
               		当前状态值为0,期望值也为0,则更改为更新值。
                    compareAndSetState(0, acquires)) {
                    线程获取锁成功,使用了CAS算法(单线程时偏向锁)(多线程时偏向锁变成轻量级锁)设置排他锁
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    public final boolean hasQueuedPredecessors() {
        // The correctness of this depends on head being initialized
        // before tail and on head.next being accurate if the current
        // thread is first in queue.
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        Node s;
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }
    protected final boolean compareAndSetState(int expect, int update) {
        // See below for intrinsics setup to support this
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }
    protected final void setExclusiveOwnerThread(Thread thread) {
        exclusiveOwnerThread = thread;
    }        

ロックの方法は、最初にvolatile変数の状態を読み出します。
公平ロックを使用する場合は、ロック解除方法ロック解除()は以下のトラックを呼び出します。

1)ReentrantLock:unlock();
2)AbstractQueuedSynchronizer:release(int arg); 
3)Sync:tryRelease(int releases);

ステップ3では、実際にロックを解除するために始めました

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);      释放锁的最后,写volatile变量state
            return free;
        }

ロックを獲得しながら、ロック解除の最後の書き込み揮発性変数でフェアロックは、最初にこの変数をお読みください。よれば、ロックを取得するために、すぐに目に見えるスレッドとなる正規揮発性前後-発生し、ロック・スレッドを取得するのと同じ揮発性変数から読み出し揮発性変数共有変数を書き込む前に可視スレッドのロックを解除します。
不当なロック解除を解放し、公正なロックがまったく同じ、そして見に不公平なロックアクセス
不公平なロックの使用を、ロック法ロック()は以下のトラックを呼び出します。

1)ReentrantLock:lock(); 
2)NonfairSync:lock();
3)AbstractQueuedSynchronizer:compareAndSetState(int expect,int update);

最初の3つは本当にロックを開始し始めました

protected final boolean compareAndSetState(int expect, int update) { 
	return unsafe.compareAndSwapInt(this, stateOffset, expect, update); }

略すのcompareAndSet()メソッド呼び出しの原子的状態変数を更新する方法であって、CASは
以下のような方法のJDKドキュメントが記載
現在の状態値が指定された更新値に期待値アトミック同期状態に等しい場合。この操作は、揮発性の読み取りと書き込みのメモリセマンティクスを持っています。

概要

公正かつ不公平ロックロック解除、そして最終的には、揮発性の変数の状態を書かなければならなかったときに
戻って、最初の揮発性の変数を読んで、ときロック取得フェア
不公平ロック取得は、CASは揮発性変数との最初の更新は、この操作はまた、揮発性の読み取りと書き込みがありますとき意味記憶

ロック解除 - 少なくとも2つの方法があります実現する取得意味記憶

揮発性の変数を使用して読むには、(1) -書き込みのメモリセマンティクスを持っています。
(2)揮発性及び不揮発性メモリの書き込みセマンティクスを伴うCASの使用。

公開された24元の記事 ウォンの賞賛1 ビュー544

おすすめ

転載: blog.csdn.net/qq_45366515/article/details/105145296