"Java concurrent programming art" of synchronized and JUC

synchrnoized的happens-before

int a;
boolean flag;
public synchronized void init(){// ①
    a = 100; // ②
    flag = true; // ③
}// ④
public synchronized void doTask(){ // ⑤
    if(flag){ // ⑥
        int result = a; // ⑦
    }
} // ⑧

Suppose thread A executed init (), thread B executed doTask (), the following happens-before relation:

  • According to the program sequence rules:
    • ① hb ②
    • ② hb ③
    • ③ hb ④
    • ⑤ hb ⑥
    • ⑥ hb ⑦
    • ⑦ hb ⑧
  • The monitor rules:
    • ① hb ④
    • ④ hb ⑤
    • ⑤ hb ⑧

The transfer rule, ensure init () method on all modifications doTask () methods can be found, happens-before relation is shown below

Indicates that the program sequence rules between 1 and 2, showing the monitor rule between 4,5 and 3,4 since there happens-before relation, there happens-before 4,5 relationship, so from the transfer rules, between 2,6 there happens-before relationship.

A thread releases the lock before all visible shared variables, after obtaining a lock in the same thread B becomes visible.

synchrnoized semantic memory

synchrnoized acquire a lock semantic memory

When the lock is released, it will JMM local memory corresponding to the thread in the main memory to refresh the shared variables. In the above example, for example, the shared state of the data mode is shown below

synchrnoized release the lock semantic memory

A thread, when the lock is acquired, JMM will the thread corresponding local memory is deasserted. So that the monitor is protected critical section of code to be read from main memory shared variables.

Semantic summary

Comparison lock release - and obtaining semantic volatile memory write - read memory semantics can be seen: the lock release volatile memory is written with the same semantics; read lock acquisition and volatile memory have the same semantics.

  • A thread releases a lock, is essentially a message to tell the other (changes made thread A) To obtain the shared variable thread
  • Thread B gets a lock, in essence receive messages sent by another thread (thread releases the lock modify the shared variable done)
  • A thread release, then thread B acquires essentially thread A sends a message to the thread B through the main memory.

Here the semantics are the same is determined by whether the same two process operations, such as the lock thread A complete release, to refresh main memory; after volatile finished, to refresh main memory, and notifies other thread local memory shared variables fail ( in the lock release link is to lock acquisition in execution);

CAS和JUC

synchronized是通过控制对象头来控制锁的升级,但是具体获取锁和释放锁的流程藏在JVM里,这里将通过ReentrantLock类比synchronized过程。

ReentrantLock的实现流程

这里要学习的是CAS,JDK文档对该方法的说明如下:如果当前状态值等于预期值,则以原子方式将同步设置为给定的更新值。此操作具有volatile读和写的语义。
前面讲到volatile写保证volatile写不会和前面的操作发生重排序,volatile读保证volatile读不会和后面的操作发生重排序。组合这两个条件就意味着同时实现了 禁止某一操作和操作前、操作后的重排序。CAS操作就是如此,它在是通过加上lock前缀来实现以下的功能:

  • 使用缓存锁定保证原子性
  • 禁止之前和之后的重排序
  • 把写缓冲区中的所有数据刷新到内存

正是因为CAS同时具有volatile读和写的内存语义,因此Java线程之间的通信有下面四种方式。

  1. A线程写volatile变量,B线程读这个volatile变量
  2. A线程写volatile变量,B线程用CAS修改volatile变量
  3. A线程用CAS修改volatile变量,B线程用CAS修改这个变量
  4. A线程用CAS修改volatile变量,B线程用volatile读取该变量

JUC包的通用化的实现模式:

  • 声明共享变量为volatile
  • 使用CAS的原子条件来实现线程间的同步
  • 配合volatile读/写和CAS 来实习线程间的通信

AQS,非阻塞数据结构和原子变量类,这些JUC包中的基础都是使用上面的模式来实现的,而JUC包的高层类又是依赖这些基础类来实现的。从整体看,JUC包的实现示意图如下所示。

Guess you like

Origin www.cnblogs.com/codeleven/p/10963109.html