synchrnoized的には事前発生
int a;
boolean flag;
public synchronized void init(){// ①
a = 100; // ②
flag = true; // ③
}// ④
public synchronized void doTask(){ // ⑤
if(flag){ // ⑥
int result = a; // ⑦
}
} // ⑧
実行INITスレッドと仮定()、スレッドBは(doTaskを実行し)、次の処理が行われ、前関係:
- 番組配列規則によると:
- ①②HB
- ②HB③
- ③HB④
- ⑤HB⑥
- ⑥HB⑦
- ⑦HB⑧
- モニターのルール:
- ①HB④
- ④HB⑤
- ⑤HB⑧
転送ルール、すべての変更doTask()メソッドのinit()メソッドを見つけることができることを確認し、事前発生関係を以下に示します。
関係が、前に起こるので4,5と3,4との間のモニタルールを示し、1と2の間のプログラムシーケンス規則ことを示し、そこに起こる、前4,5関係ので、転送ルールから、2,6間そこに事前発生関係を。
スレッドは、同じスレッドBにロックを取得した後に見えるようになり、すべての可視の共有変数前にロックを解除します。
synchrnoized意味記憶
ロック意味記憶を獲得synchrnoized
ロックが解除されると、それは共有変数を更新するには、メインメモリ内のスレッドに対応したローカルメモリをJMMます。上記の例では、例えば、データモードの共有状態を以下に示します。
ロックセマンティックメモリを解放synchrnoized
スレッドは、ロックが取得されたときに、JMMは、ローカルメモリに対応するスレッドがデアサートされます。モニターが保護されるように、コードのクリティカルセクションは、メインメモリ共有変数から読み取られます。
セマンティック概要
比較ロック解除 - とセマンティック揮発性メモリの書き込みを取得する - メモリのセマンティクスを読んで見ることができます:ロック解除揮発性メモリは、同じ意味で書かれている、ロック取得と揮発性メモリを読んで、同じ意味を持ちます。
- スレッドは、ロックを解除する、本質的に共有変数スレッドを得るために、他の(スレッドAの変更)を指示するメッセージであります
- スレッドBは、別のスレッドによって送信されたメッセージを受信本質的には、ロックを取得します(スレッドがロックが行われ、共有変数を変更リリース)
- 次いで、スレッド放出、Bは、本質的にAがメインメモリを介して、スレッドBにメッセージを送信するスレッド取得スレッド。
(揮発性完成した後に、メイン・メモリをリフレッシュするために、そして他のスレッドローカルメモリ共有変数が失敗通知する。ここで意味は同じであるようなロックと同じ2つのプロセスの操作は、メイン・メモリをリフレッシュするために、完全な放出を通すか否かによって決定されますロック解除リンクで実行中の取得)をロックすることです。
CAS和JUC
synchronized是通过控制对象头来控制锁的升级,但是具体获取锁和释放锁的流程藏在JVM里,这里将通过ReentrantLock类比synchronized过程。
这里要学习的是CAS,JDK文档对该方法的说明如下:如果当前状态值等于预期值,则以原子方式将同步设置为给定的更新值。此操作具有volatile读和写的语义。
前面讲到volatile写保证volatile写不会和前面的操作发生重排序,volatile读保证volatile读不会和后面的操作发生重排序。组合这两个条件就意味着同时实现了 禁止某一操作和操作前、操作后的重排序。CAS操作就是如此,它在是通过加上lock前缀来实现以下的功能:
- 使用缓存锁定保证原子性
- 禁止之前和之后的重排序
- 把写缓冲区中的所有数据刷新到内存
正是因为CAS同时具有volatile读和写的内存语义,因此Java线程之间的通信有下面四种方式。
- A线程写volatile变量,B线程读这个volatile变量
- A线程写volatile变量,B线程用CAS修改volatile变量
- A线程用CAS修改volatile变量,B线程用CAS修改这个变量
- A线程用CAS修改volatile变量,B线程用volatile读取该变量
JUC包的通用化的实现模式:
- 声明共享变量为volatile
- 使用CAS的原子条件来实现线程间的同步
- 配合volatile读/写和CAS 来实习线程间的通信
AQS,非阻塞数据结构和原子变量类,这些JUC包中的基础都是使用上面的模式来实现的,而JUC包的高层类又是依赖这些基础类来实现的。从整体看,JUC包的实现示意图如下所示。