并发三大性质

1. 原子性

一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。

  1. 例如:a++;这个操作其实分成以下3步进行:
    (1)读取a的值;
    (2)将a的值加1;
    (3)将加1后的值赋给a;
    在多个线程同时操作这条语句的时候,如果A线程刚对a变量进行+1操作后还没来得及重新赋值给a,就被B线程读取到了a的值然后进行了+1的操作,那么A线程并没有完全执行完这3步操作就被B线程读取了这个变量,就不能保证原子性了。
  2. 如何保证原子性
    (1)通过 synchronized 关键字定义同步代码块或者同步方法保障原子性。
    (2)通过 Lock 接口保障原子性。
    (3)通过 Atomic 类型保障原子性。
2. 可见性

一个线程对共享变量的修改,能够及时的被其他线程看到。

  1. 共享变量
    如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量。
  2. Java内存模型
    Java内存模型(Java Memory Model)描述了Java程序中各种变量(共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取出变量这样的底层信息。
    (1)所有的变量都存储在主内存中;
    (2)每个线程都有自己独立的工作内存,里面保存该线程使用到的变量的副本。
    (3)每个线程对共享变量的操作都必须在自己的工作内存中进行,不能直接从主内存中读写。
    (4)不同线程之间无法直接访问彼此工作内存中的变量,不同线程间变量值的传递需要通过主内存来完成。在这里插入图片描述
  3. 可见性实现原理
    (1)把线程中修改的变量值先更新到该线程独立的工作内存中,再将工作内存中的值刷新到主内存中。
    (2)主内存再将最新的共享变量的值刷新到其他工作内存中。
  4. 如何保证可见性
    (1)通过 synchronized 关键字定义同步代码块或者同步方法保障可见性。
    (2)通过 volatile 关键字标记内存屏障保证可见性。volatile 的特殊规则保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。但是volatile 不能保证原子性。
    (3)通过 Lock 接口保障可见性。
    (4)通过 Atomic 类型保障可见性。
    (5)通过 final 关键字保障可见性
3. 有序性

即程序执行的顺序按照代码的先后顺序执行。

  1. 不过处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。 例如:
    int i=1;//语句1
    int j=2;//语句2
    在执行时,有可能对代码进行重排序,比如先执行语句2,再执行语句1。但是如果代码,编程下边这样:
    int i=1;
    int j=2;
    j++;//语句3
    i=j+1;//语句4
    这时,语句3和语句4并不会进行重排序。因为语句3和4之间有依赖关系,重排序后会影响结果。
    但是在多线程的情况下,就可能会出错。例如:
    boolean flag=false;
    private int i=1;
    //线程1
    i += 1;//语句1
    flag=true;//语句2
    //线程2
    if(flag){
    j += i;
    }
    如果线程1执行的时候,语句1和语句2进行了重排序,先执行语句2,在还没有执行语句1时,这时线程2 将要执行if,那么就会进入到if语句块中,这时候j的值就会出错。
  2. 如何保证有序性
    (1)通过 synchronized 关键字通过一个变量在同一时刻只允许一条线程对其进行lock操作来保证其线程访问的有序性。
    (2)可以用volatile关键字,禁止被它修饰的变量发生指令重排操作。是通过内存屏障去完成的禁止指令重排序。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值