JAVA 线程 Synchronized Volatile

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_31482599/article/details/88564206

概念

  • 线程:程序执行流的最小单元。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。
  • 线程有就绪、阻塞和运行三种基本状态。就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。
  • 每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。
  • 在单个程序中同时运行多个线程完成不同的工作,称为多线程。

特性

  • 原子性(Atomicity):

指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行。

  • 可见性(Visibility):

可见性就是指当一个线程修改了线程共享变量的值,其它线程能够立即得知这个修改。Java内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值这种依赖主内存作为传递媒介的方法来实现可见性的,无论是普通变量还是volatile变量都是如此,普通变量与volatile变量的区别是volatile的特殊规则保证了新值能立即同步到主内存,以及每使用前立即从内存刷新。因为我们可以说volatile保证了线程操作时变量的可见性,而普通变量则不能保证这一点。

  • 有序性(Ordering)

Java内存模型中的程序天然有序性可以总结为一句话:如果在本线程内观察,所有操作都是有序的;如果在一个线程中观察另一个线程,所有操作都是无序的。前半句是指“线程内表现为串行语义”,后半句是指“指令重排序”现象和“工作内存中主内存同步延迟”现象。
Java语言提供了 volatilesynchronized 两个关键字来保证线程之间操作的有序性。

  • volatile关键字本身就包含了禁止指令重排序的语义,
  • synchronized则是由“一个变量在同一时刻只允许一条线程对其进行lock操作”这条规则来获得的(当不满足时,会将其线程放到Wait Set 中),这个规则决定了持有同一个锁的两个同步块只能串行地进入。
可见性:一个线程对共享变量值的修改,能够及时地被其他线程看靠
共享变量:如果一个线程在多个线程的工作内存中都存在副本,那么这个变量就是几个线程的共享变量

JAVA 内存模型

java内存模型(JMM)描述了JAVA程序中各种变量 (线程共享变量) 的访问规则,以及在JVM中将变量存储到内存和从内从中读取出变量这样的底层细节。

所有的变量都存储在主内存中
每个线程都有自己独立的工作内存,里面保存该线程使用到的变量的副本(主内存中该变量的一份拷贝)

在这里插入图片描述

两条规定:
  • 线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接从主内粗中读写
  • 不同线程之间无法直接访问其他线程工作内存中的变量,线程间变量的传递需要通过主内存来完成。
共享变量可见性的实现原理:

线程1对共享变量的修改要想被线程2及时看到,必须要经过如下两个步骤
1、把工作内存1中更新过的共享变量刷新到主内存中
2、将主内存中最新的共享变量的值更新到工作内存2中

可见性:

要实现共享变量的可见性,必须保证两点:
1、线程修改后的共享变量值能及时从工作内粗中刷新到主内存中
2、其它线程能及时把共享变量的最新值从主内存中更新到自己的工作内存中

JAVA 语言层面支持的可见性实现方式:

  • synchronized:能实现原子性(同步)和可见性
  • volatile:可以保证变量的可见性,不能保证变量复合操作的原子性
synchronized
  • JMM 关于的两条规定:
    1.线程解锁前,必须把共享变量的最新值刷新到主内存中
    2.线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时要从住内存中重新读取最新的值(注:加锁与解锁是同一把锁)

  • 线程解锁前对共享变量的修改在下次加锁时对其他线程可见:
    线程执行互斥代码的过程:
    1.获得互斥锁
    2.清空工作内存
    3.从住内存拷贝变量的最新副本到工作内存
    4.执行代码
    5.将更改后的共享变量的值刷新到主内存
    6.释放互斥锁
    重排序:ulr????????
    重排序:代码书写的顺序与实际执行的顺序不同,指令重排序是编译器或处理器为了提高程度性能而做的优化
    1.编译器优化的重排序(编译器优化)
    2.指令级并行重排序(处理器优化)
    3.内存系统的重排序(处理器优化)
    多线程中程序交错执行时,重排序可能会造成内存可见性问题

volatile
  • 通过加入内存屏障和禁止重排序优化来实现的
    1.对volatile变量执行写操作时,会在写操作后加入一条store屏障指令
    2.对volatile变量执行读操作时,会在读操作前加入一条load屏障指令

  • volatile如何实现内存可见性:
    volatile变量每次被线程访问时,都强迫从主内存中重读该变量的值,而当该变量发生变化时,又强迫线程将最新的值刷新到主内存中。这样任何时刻不同线程总能可能都该变量的最新值

    扫描二维码关注公众号,回复: 5683909 查看本文章
  • 线程写volatile 变量的过程:
    1.改变线程工作内存中volatile变量副本的值
    2.将改变后的副本的值从工作内存刷新到主内存

  • 线程读volatile变量的过程:
    1.从主内存中读取volatile变量的最新值到线程的工作内存中
    2.从工作内存中读取volatile变量的副本

猜你喜欢

转载自blog.csdn.net/qq_31482599/article/details/88564206