美文网首页Java学习笔记
java并发编程的艺术读后感

java并发编程的艺术读后感

作者: WANGGGGG | 来源:发表于2019-03-31 20:38 被阅读6次

    一、java内存模型

    java内存模型属于语言级的内存模型,它确保在不同的编译器和不同的处理器平台之上,通过禁止特定类型的编译器重排序和处理器重排序,为程序员提供一致的内存可见保证。JMM不保证未同步程序执行结果与该程序在顺序一致性模型中的执行结果一致,因为如果想要保证执行结果一致,JMM需要禁止大量处理器和编译器的优化,这对于程序的执行性能会产生很大的影响。

    二、 原子操作的实现原理

    (1)使用总线锁保证原子性,(2)使用缓存锁定保证原子性。

    三、Volatile应用

    Volatile可以算是轻量级的synchronized,它在多处理器开发中保证了共享变量的可见性,即一个线程在修改一个共享变量时,另外一个线程能读到这个修改的值。

    3.1特性:

    (1) 可见性:读一个volatile变量时,总能看到对这个变量最后的写入操作
    (2) 原子性:对于任意单个volatile变量的读/写具有原子性(但是volatile++这种复合操作不具有原子性)

    3.2实现原理

    Volatile修饰的共享变量转成汇编代码时会多出一个lock开头的指令,该指令实际效益为:(1)Lock前缀指令会引起处理器缓存回写到内存,如果访问的内存区域已经缓存在处理器内部,则不会声言lock信号,相反它会锁定这块内存区域的缓存并回写到内存,并使用缓存一致性机制来确保修改的原子性,此操作被称为缓存锁定,缓存一致性机制会阻止同时修改由两个以上处理器缓存的内存区域数据;(2)一个处理器的缓存回写到内存会导致其他处理器的缓存无效。在多核处理器系统中进行操作的时候,IA-32和intel64处理器能嗅探其他处理器访问系统内存和它们的内部缓存。处理器使用嗅探技术保证它的内部缓存、系统内存和其他处理器的缓存的数据在总线上保持一致。
    在多处理器下,为了保证各个处理器的缓存是一致的,就会实现缓存一致性协议,每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存里。

    3.3volatile的使用优化

    追加字节优化性能,是因为有些处理器的高速缓存行是64个字节宽,不支持部分填充缓存行,这意味着如果队列头节点和尾节点都不足64个字节的话,处理器会将他们都读到同一个高速缓存行中,多处理器的情形下,每个处理器都会缓存同样的头尾节点,当一个处理器试图修改头节点时,会将整个缓存行锁定,根据缓存一致性的原则,其他处理器便不能访问自己高速缓存中的尾节点,但是队列的出入操作需要不停的修改头节点和尾节点,所以多处理器情况下追加到64字节可以优化处理速度。
    注:当缓存行非64字节时,不需要追加,共享变量不是很频繁的被读取时也不需要追加操作。

    四、Synchronized实现原理与应用

    锁一共有4中状态,从低到高分别为:无锁状态,偏向锁状态,轻量级锁状态,重量级锁状态。Synchronized用户锁是存在对象头里面的。
    自旋:如果持有锁的线程能在很短的时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,他们只需要等一下(自旋),等待锁释放后即可马上获取锁,这样就避免了用户线程和内核的切换消耗。

    是什么 优点 缺点 适用场景
    偏向锁 它会偏向第一个访问锁的线程,如果接下来的运行过程中,该锁没有被其他的线程访问,则持有偏向锁的线程将永远不会触发同步,如果在运行过程中,遇到了其他线程会被挂起,JVM会尝试消除它身上的偏向锁,将锁恢复到轻量级锁 加锁和解锁不需要额外的消耗,和执行非同步方法相比仅存在纳秒级别的差距 如果线程之间的存在锁竞争,会带来额外的锁撤销的消耗 适用于只有一个线程访问同步块场景
    轻量级锁 线程在执行同步块之前,JVM会先在当前线程的栈帧中创建用于存储锁记录的空间,并将对象头中的Mark word复制到锁记录中,官方称为Displaced Mark Word。然后线程尝试使用CAS将对象头中的mark word替换为指向锁记录的指针,如果成功,当前线程获得锁,如果失败,则表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。 竞争的线程不会阻塞,提高了程序的响应速度 如果始终得不到锁竞争的线程,使用自旋锁会消耗cpu 追求响应时间,同步块执行速度非常快
    重量级锁 / 线程竞争不使用自旋,不会消耗cpu 线程阻塞,响应时间缓慢 追求吞吐量,同步块执行速度较慢

    五、公平锁与非公平锁

    公平锁和非公平锁释放时最后都需要写一个volatile变量state,公平锁获取时,首先会
    去读volatile变量;非公平锁获取时,首先会用CAS更新volatile变量,这个操作同时具有volatile读写语义。|

    六、内存语义:

    6.1 Volatile内存语义:

    JMM会限制volatile会限制读写操作的重排序(1)在每个写操作前面插入一个StoreStore屏障,防止普通写和volatile写重排序;在每个volatile写操作的后面插入一个StoreLoad屏障,防止volattile和后面的读写操作重排序。(2)在每个volatile读操作后面加入LoadLoad屏障,防止普通读和volatile重排序;在每个volatile读操作后面插入一个LoadStore屏障,防止被后面的普通写操作重排序。

    6.2 Final域内存语义:

    (1) JMM禁止编译器把final域的写重排序到构造函数之外;
    (2) 编译器会在final的写之后,构造函数return之前,插入一个StoreStore屏障,屏障会禁止处理器把final域的写重排序到构造函数之外,即阻止其溢出。
    双重检查锁定以及延迟初始化:
    (1) A线程去访问类对象X,此时它会取得锁,发现X没有初始化,将其标记为正在初始化,这个时候释放锁。
    (2) B线程去访问X,获取锁,发现X正在初始化,释放锁
    (3) A初始化X完毕,获取锁,设置状态为已初始化,释放锁
    (4) B线程去访问X,获取锁,发现它已经初始化好了,获取这个类对象,释放锁

    原创文章转载请标明出处
    更多文章请查看
    http://www.canfeng.xyz

    相关文章

      网友评论

        本文标题:java并发编程的艺术读后感

        本文链接:https://www.haomeiwen.com/subject/gknubqtx.html