多线程相关(5)

JMM

Java 内存模型(Java Memory Model,JMM)就是一种符合内存模型规范的,屏蔽了各种硬件和操作系统的访问差异的,保证了 Java 程序在各种平台下对内存的访问都能保证效果一致的机制及规范
主存-内存-三级缓存
JMM 是一种规范,是解决由于多线程通过共享内存进行通信时,存在的本地内存数据不一致、编译器会对代码指令重排序、处理器会对代码乱序执行等带来的问题
目的是保证并发编程场景中的原子性、可见性和有序性

原子性

在 Java 中,为了保证原子性,提供了两个高级的字节码指令 Monitorenter 和 Monitorexit。这两个字节码,在 Java 中对应的关键字就是 Synchronized。因此,在 Java 中可以使用 Synchronized 来保证方法和代码块内的操作是原子性的

可见性

Java 中的 Volatile 关键字修饰的变量在被修改后可以立即同步到主内存。被其修饰的变量在每次使用之前都从主内存刷新。因此,可以使用 Volatile 来保证多线程操作时变量的可见性。除了 Volatile,Java 中的 Synchronized 和 Final 两个关键字也可以实现可见性。只不过实现方式不同。

有序性

在 Java 中,可以使用 Synchronized 和 Volatile 来保证多线程之间操作的有序性。区别:Volatile 禁止指令重排。Synchronized 保证同一时刻只允许一条线程操作

volatile底层实现

作用

保证数据的“可见性”:被volatile修饰的变量能够保证每个线程能够获取该变量的最新值,从而避免出现数据脏读的现象。
禁止指令重排:在多线程操作情况下,指令重排会导致计算结果不一致。
底层实现:
“观察加入volatile关键字和没有加入 volatile 关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个 lock 前缀指令”
lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:
1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;
2)它会强制将对缓存的修改操作立即写入主存;
3)如果是写操作,它会导致其他CPU中对应的缓存行无效。
单例模式中volatile的作用:
防止代码读取到 instance 不为 null 时,instance 引用的对象有可能还没有完成初始化。

public class Singleton {
    private volatile static Singleton instance = null;//禁止指令重排    
    private Singleton() {}    
    
    public static Singleton getInstance() {        
        if(instance==null) { //减少加锁的损耗            
            synchronized (Singleton.class) {                
                if(instance==null) //确认是否初始化完成                    
                    instance = new Singleton();            
            }        
        }        
        return instance;    
    }
}

AQS思想

AQS的全称为(AbstractQueuedSynchronizer)抽象的队列式的同步器,是⼀个⽤来构建锁和同步器的框架。使⽤AQS能简单且⾼效地构造出应⽤⼴泛的⼤量的同步器,如:基于 AQS 实现的 lock, CountDownLatch、CyclicBarrier、Semaphore需解决的问题:状态的原子性管理线程的阻塞与解除阻塞队列的管理

AQS核⼼思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的⼯作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占⽤,那么就需要⼀套线程阻塞等待以及被唤醒时锁分配的机制,这个机制AQS是⽤ CLH(虚拟的双向队列)队列锁实现的,即将暂时获取不到锁的线程加⼊到队列中。

lock

是一种可重入锁,除了能完成 synchronized 所能完成的所有工作外,还提供了诸如可响应中断锁、可轮询锁请求、定时锁等避免多线程死锁的方法默认为非公平锁,但可以初始化为公平锁;通过**方法 lock()与 unlock()**来进行加锁与解锁操作;

CountDownLatch

通过计数法(倒计时器),让一些线程堵塞直到另一个线程完成一系列操作后才被唤醒;该⼯具通常⽤来控制线程等待,它可以让某⼀个线程等待直到倒计时结束,再开始执⾏。具体可以使用countDownLatch.await() 来等待结果。多用于多线程信息汇总

CompletableFuture

通过设置参数,可以完成 CountDownLatch 同样的多平台响应问题,但是可以针对其中部分返回结果做更加灵活的展示。

CyclicBarrier

字面意思是可循环(Cyclic)使用的屏障(Barrier)。他要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活,线程进入屏障通过 CyclicBarrier 的 await() 方法。可以用于批量发送消息队列信息、异步限流

Semaphore

信号量主要用于两个目的,一个是用于多个共享资源的互斥作用,另一个用于并发线程数的控制。SpringHystrix限流的思想。

happens-before

用来描述和可见性相关问题:
如果第一个操作 happens-before 第二个操作,那么我们就说第一个操作对于第二个操作是可见的。
常见的happens-before:volatile 、锁、线程生命周期

原文:https://mp.weixin.qq.com/s/IVgGXQKU1QiT1ToN2wXHJg

  • 28
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值