Art concurrent programming - notes (b)

Foreword

After compiling Java code into Java bytecode, the bytecode classes loaded into the JVM, JVM byte code execution, must be transformed into the final assembly instruction execution on the CPU, complicated mechanisms rely on Java used the JVM implementation and CPU instruction. In this chapter we will explore in depth at the bottom with the underlying Java concurrency mechanisms of implementation principle .

problem

What is volatile
the synchronized reference and the principle of
what is java object head lock upgrade process? What is biased locking
What is an atomic operation? How to achieve an atomic operation
What CAS lock is? Cause those problems

volatile applications

In multi-threaded programming synchronized and volatile plays an important role, volatile lightweight synchronized, it ensures the "visibility" of shared variables in a multiprocessor development. ( Atom visibility. Just focus ) which is lower than the cost of execution and use of synchronized, because it does not cause the thread context switching and scheduling. ( This understanding is synchronized reverse wave will cause a context switch, is really so? Accurate to say that the use of the synchronized keyword, resulting competition for resources, causing a context switch. ) This article will be in-depth analysis on the hardware level how Intel processor is the realization volatile.

The definition and implementation of the principles of volatile

Java Language Specification Version 3 definition of volatile follows: Java programming language allows threads to access shared variables, in order to ensure shared variables can be accurately and consistently updated thread should ensure exclusive lock to get through this variable alone. Java language provides volatile, and in some cases to be more convenient than lock. If a field is declared as volatile, Java thread memory model ensures that all threads see the value of this variable is the same.

Let's explain the specific implementation of the principle of two volatile.

1) Lock prefix instructions cause the processor cache is written back to memory
2) a processor's cache memory is written back to causes other processor's cache is invalid.
If the interviewer asks you about the volatile underlying implementation, you can know the result of these two very Niubi, if you could clarify the principles involved, you are flying cow pen plus

optimization of the use of volatile

Well, this section there are interested students can read on their own Kazakhstan, ending not test

Principles and Applications of synchronized implementation

Use synchronized basis to achieve synchronization: Java each object can be used as a lock. Specific performance in the following three forms.

For normal synchronization method, the lock is the current instance of the object.
For static synchronized method, the lock is Class object of the current class.
A method for synchronizing blocks, the object lock is configured Synchonized brackets.
Understand this place, you need to know the class is an abstract object, the object is an instance of the class

When a thread attempts to access synchronized block, it must first get the lock, the lock must be released when you exit or throw an exception. So where in the end there is lock it? What information is stored inside the lock it?

JVM specification can be seen from the realization of the principle of Synchonized in the JVM, JVM synchronization and block synchronization based on entry and exit Monitor object to implement the method, but the implementation details of the two are not the same. Block synchronization is achieved using monitorenter and monitorexit instructions, and the method of synchronization is implemented using another way, details not described in detail in the JVM specification . However, the same method may be used in the synchronization of these two instructions.
monitorenter instruction is compiled at the start position of the synchronization code is inserted into the block and monitorexit is inserted into the end of the methods and exception, the JVM monitorenter to ensure that each must have a corresponding paired monitorexit. Any object has associated with it a monitor, and a monitor after being held, it is locked. When the thread execution to monitorenter instruction, will attempt to acquire ownership of the object corresponding to the monitor, that is trying to get a lock object.

Java object header

The lock is synchronized with the advance of the presence of Java objects. If the object is an array type, the virtual machine with three words wide (Word) storage object header, if the subject is a non-array type, with a word-wide memory object header 2. In the 32-bit virtual machine, a word width equal to 4 bytes, i.e. 32bit, as shown below.

Here Insert Picture Description
Mark Word ahead of Java objects in the default storage object HashCode, age and generational lock flag. As shown in the default storage structure Mark Word 32 follows the JVM.
Here Insert Picture Description
During operation, the data stored in the Mark Word will vary with the lock flag. Mark Word may be changed to the following four data store, as shown below.
Here Insert Picture Description
In the 64-bit virtual machine, Mark Word is 64bit size, which storage structure as shown in FIG.
Here Insert Picture DescriptionTo address this knowledge allow me to give you leave homework. Integer object total memory size? This one I always will be the subject of the interview to examine the developer's understanding of the underlying. Oh interview test sites

锁的升级与对比

在 Java SE 1.6中,锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级。这种锁升级却不能降级的策略,目的是为了提高获得锁和释放锁的效率,下文会详细分析。

偏向锁

HotSpot[1]的作者经过研究发现,大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。

(1)偏向锁的撤销
Here Insert Picture Description
(2)关闭偏向锁

偏向锁在Java 6和Java 7里是默认启用的,但是它在应用程序启动几秒钟之后才激活,如有必要可以使用JVM参数来关闭延迟:-XX:BiasedLockingStartupDelay=0。如果你确定应用程序里所有的锁通常情况下处于竞争状态,可以通过JVM参数关闭偏向锁:-XX:-
UseBiasedLocking=false,那么程序默认会进入轻量级锁状态。

轻量级锁
(1)轻量级锁加锁

线程在执行同步块之前,JVM会先在当前线程的栈桢中创建用于存储锁记录的空间,并 将对象头中的Mark Word复制到锁记录中,官方称为Displaced Mark Word。然后线程尝试使用 CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失 败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。

(2)轻量级锁解锁

轻量级解锁时,会使用原子的CAS操作将Displaced Mark Word替换回到对象头,如果成 功,则表示没有竞争发生。如果失败,表示当前锁存在竞争,锁就会膨胀成重量级锁。图2-2是 两个线程同时争夺锁,导致锁膨胀的流程图。
Here Insert Picture Description

因为自旋会消耗CPU,为了避免无用的自旋(比如获得锁的线程被阻塞住了),一旦锁升级 成重量级锁,就不会再恢复到轻量级锁状态。当锁处于这个状态下,其他线程试图获取锁时, 都会被阻塞住,当持有锁的线程释放锁之后会唤醒这些线程,被唤醒的线程就会进行新一轮的夺锁之争。

锁的优缺点对比
Here Insert Picture Description
下面这张图能够吃透,就可以出师了
Here Insert Picture Description

原子操作的实现原理

原子(atomic)本意是“不能被进一步分割的最小粒子”,而原子操作(atomic operation)意 为“不可被中断的一个或一系列操作”。

术语定义

处理器如何实现原子操作
这两个知识点有兴趣的同学一样可以自行阅读哈,下节课抽问回答

Java如何实现原子操作

在Java中可以通过锁和循环CAS的方式来实现原子操作。
(1)使用循环CAS实现原子操作

JVM中的CAS操作正是利用了处理器提供的CMPXCHG指令实现的。自旋CAS实现的基本 思路就是循环进行CAS操作直到成功为止。

从Java 1.5开始,JDK的并发包里提供了一些类来支持原子操作,如AtomicBoolean(用原子方式更新的boolean值)、AtomicInteger(用原子方式更新的int值)和AtomicLong(用原子方式更新的long值)。这些原子包装类还提供了有用的工具方法,比如以原子的方式将当前值自增1和自减1。

(2)CAS实现原子操作的三大问题

1)ABA问题。

因为CAS需要在操作值的时候,检查值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它 的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加1,那么A→B→A就会变成1A→2B→3A。从 Java 1.5开始,JDK的Atomic包里提供了一个类AtomicStampedReference来解决ABA问题。这个 类的compareAndSet方法的作用是首先检查当前引用是否等于预期引用,并且检查当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。

   	/**
     * Atomically sets the value of both the reference and stamp
     * to the given update values if the
     * current reference is {@code ==} to the expected reference
     * and the current stamp is equal to the expected stamp.
     *
     * @param expectedReference the expected value of the reference
     * @param newReference the new value for the reference
     * @param expectedStamp the expected value of the stamp
     * @param newStamp the new value for the stamp
     * @return {@code true} if successful
     */
    public boolean compareAndSet(V   expectedReference,
                                 V   newReference,
                                 int expectedStamp,
                                 int newStamp) {
        Pair<V> current = pair;
        return
            expectedReference == current.reference &&
            expectedStamp == current.stamp &&
            ((newReference == current.reference &&
              newStamp == current.stamp) ||
             casPair(current, Pair.of(newReference, newStamp)));
    }
V expectedReference, // 预期引用
V newReference, // 更新后的引用
int expectedStamp, // 预期标志
int newStamp // 更新后的标志

2)循环时间长开销大。

自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销。如果JVM能支持处理器提供的pause指令,那么效率会有一定的提升。pause指令有两个作用:第 一,它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间 取决于具体实现的版本,在一些处理器上延迟时间是零;第二,它可以避免在退出循环的时候 因内存顺序冲突(Memory OrderViolation)而引起CPU流水线被清空(CPU Pipeline Flush),从而 提高CPU的执行效率。

3)只能保证一个共享变量的原子操作。

当对一个共享变量执行操作时,我们可以使用循 环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁。还有一个取巧的办法,就是把多个共享变量合并成一个共享变量来操作。比如,有两个共享变量i=2,j=a,合并一下ij=2a,然后用CAS来操作ij。从Java 1.5开始,JDK提供了AtomicReference类来保证引用对象之间的原子性,就可以把多个变量放在一个对象里来进行CAS操作。

(3)使用锁机制实现原子操作

Lock mechanism ensures that only the memory area of the thread to acquire a lock to be able to operate the lock. JVM internals to a variety of locking mechanism, biased lock, lock and lightweight mutex. It is interesting that in addition to biased locking, JVM achieve locking methods are used cycle CAS, that is, when a thread wants to enter the synchronized block when using a loop CAS way to get a lock when it exits sync block used when cycling CAS release the lock.

summary

In this chapter we study together the realization of the principle volatile, synchronized and atomic operations. Most Java container and the frame are dependent on the volatile and atomic operation principles described in this chapter achieved.
Address counter with source code github:

https://github.com/PandaProgramApe/ape-current

To praise the look, habit. Welcome panda program a walking ape, next goodbye

attention
Article continuously updated, can micro-channel search "panda program ape a" first time to urge more
the public

Published 18 original articles · won praise 20 · views 80000 +

Guess you like

Origin blog.csdn.net/qq_35764295/article/details/103996541