java并发之初识

一:并发编程的难点

1:原子性问题

  • 操作系统做任务切换,可以发生在任何一条CPU指令执行完成后;
  • CPU能保证的原子操作是指令级别的,而不是高级语言的操作符;
    n++不是原子操作的,而是3条指令
    在这里插入图片描述

2:可见性问题

  • 可见性是指一个线程对一个变量进行修改,另外一个线程可以看的到
  • 可见性问题是由CPU的缓存导致的,多核CPU均有各自的缓存,这些缓存要与内存进行同步。(其实就是多线程环境下,一个线程对一个变量的改变了,而另一个线程没看到,那么的话还是按照原来的变量的值进行计算的话,那么就会出错)。

3:有序性问题

  • 在执行程序时,为了提高性能,编译器和处理器常常会对指令做重排序;
  • 重排序不会影响单线程的执行结果,但是在并发情况下,可能会出现诡异的BUG。
    在这里插入图片描述

二:并发编程

1:并发编程的目标

解决多核多线程下,造成的 缓存不一致问题,指令重排问题,处理器优化问题

  • 在cpu和主存之间添加缓存,在多线程下会存在缓存一致性问题(可见性问题)
  • 处理器内部为了使运算单元尽可能的被充分利用,处理器可能会对输入的代码进行乱序处理。这就是处理器优化。(原子性问题)
  • 很多编程语言的编译器也会有类似的优化,比如Java虚拟机的即时编译器(JIT)也会做指令重排。(指令重排问题)

2:并发编程的内存模型

  • 为了保证共享内存的正确性(可见性、有序性、原子性),内存模型定义了共享内存系统中多线程程序读写操作行为的规范。
  • 通过这些规则来规范对内存的读写操作,从而保证指令执行的正确性。它与处理器有关、与缓存有关、与并发有关、与编译器也有关。他解决了CPU多级缓存、处理器优化、指令重排等导致的内存访问问题,保证了并发场景下的一致性、原子性和有序性。

3:这个内存模型是什么

  • JMM是Java Memory Model的缩写,Java线程之间的通信由JMM控制,即JMM决定一个线程对共享变量的写入何时对另一个线程可见。
  • JMM定义了线程和主内存之间的抽象关系,通过控制主内存与每个本地内存(抽象概念)之间的交互,JMM为Java程序员提供了内存可见性的保证。
  • JMM是一种规范,目的是解决由于多线程通过共享内存进行通信时,存在的本地内存数据不一致、编译器会对代码指令重排序、处理器会对代码乱序执行等带来的问题。

4:源代码和指令间的重排序

为了提高性能,编译器和处理器常常会对指令做重排序。重排序有3种类型,其中后2种都是处理器重排序。这些重排序可能会导致多线程程序出现内存可见性问题。

  • 1.编译器优化重排序:编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
  • 2.指令级并行重排序:现代处理器采用了指令级并行技术来将多条指令重叠执行,如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
  • 3.内存系统的重排序:由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。
    在这里插入图片描述

5:解决CPU带来的重排序

  • CPU内存屏障:
    • 1.LoadLoad:禁止读和读的重排序;
    • 2.StoreStore:禁止写和写的重排序,
    • 3.LoadStore:禁止读和写的重排序,
    • 4.StoreLoad:禁止写和读的重排序。
  • Java内存屏障:
public final class Unsafef{
public native void loadFence();//LoadLoad LoadStore
public native void storeFence();//StoreStore LoadStore
public native void fullFence();//loadFence()+storeFence()+StoreLoad
}

6:解决编译器带来的重排序

(1):如何解决

JMM使用nappens-before规则来阐述操作之间的内存可见性,以及什么时候不能重排序。在JMM中如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须要存在nappens-.before:关系。换个角度来说,如果A happens-before B,则意味着A的执行结果必须对B可见,也就是保证跨线程的内存可见性。其中,前4条规则与程序员密切相关。

  • 1.程序顺序规则:一个线程中的每个操作,happens-before于(对…可见)该线程中的任意后续操作,
  • 2.volatile?变量规则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读,
  • 3.synchronized规则:对一个锁的解锁,happens-before于随后对这个锁的加锁,
  • 4.传递性:若A happens-.before B,且B happens-before C,则A happens-before C,
  • 5.start()规则:若线程A执行Thread.start(0,则线程A的start()操作nappens-before于线程B中的任意操作,
  • 6.join规则:若线程A执行ThreadB.join0并成功返回,那么线程B中的任意操作happens-.before于线程A从ThreadB.join0的成功返回。

(2):关键字vlatile

  • 4.1 volatile的基本特性
    • 可见性:对一个volatile变量的读,总是能看到对这个volatile变量最后的写入:
    • 原子性:对任意单个volatile变量的读/写具有原子性,但类似volatile++这种复合操作不具有原子性。
  • 4.2 volatilet的内存语义
    • 写内存语义:当写一个volatile变量时,JMM会把该线程本地内存中的共享变量的值刷新到主内存
    • 读内存语义:当读一个volatile变量时,JMM会把该线程本地内存置为无效,使其从主内存中读取共享变量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天天向上的菜鸡杰!!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值