前言
提示:这里为每天自己的学习内容心情总结;
Learn By Doing,Now or Never,Writing is organized thinking.
提示:以下是本篇文章正文内容
一、今天学习了什么?
- 原子性;
- CAS;
- Java内存模型;
- volatile
- Redis;
二、关于问题的答案
1.原子性
Q:什么是原子性?
原子性指的是,这个操作或者这组操作不能被中断,必须一气呵成。
Q:处理器如何实现原子性?
处理器通过两种操作保证原子性:总线锁定、缓存锁定。
「总线锁定」,指的是一个处理器发射出 LOCK 信号,然后其它的处理器接收到这个信号后,不能和主存进行交互,保证了当前时刻只能有一个处理器独占内存。
「缓存锁定」,由于总线锁定是一个并发度低的操作,其它的处理器都不能和主存进行沟通交流。所以,引入「缓存锁定」。缓存锁定是,每次更新处理器缓存中的数据,由缓存一致性协议(MESI)保证缓存一致性。
Q:Java如何实现原子性?
Java中通过「锁」和「循环CAS」保证原子性。
2.CAS
Q:什么是CAS?
CAS 的全称是比较和交换,是乐观锁的思想,搭配「volatile」关键字可以实现无锁并发。
主要有三个变量:
- 内存地址,v;
- 当前值,A;
- 更新值,B;
如果内存地址的值和A相同,则将内存地址的值更新为B。
Q:CAS的底层实现原理?
CAS 的底层实现原理,是通过 Unsafe 类的三个 native 方法,compareAndSwapXXXX;
这三个方法对应的是通过调用操作系统的一个原语实现的,CMPXCHG,由操作系统保证完成。
Q:CAS可能导致的三个问题?
「ABA」问题,如果某个线程将共享数据从A修改为B,最后又修改成A。这个修改过程,是无法被感知到的,因为CAS只是判断内存地址的数据结果。
针对这个问题,JDK 有两个实现类解决了,通过给共享数据加版本号的方式,这两个实现类是:AtomicStampedReference、AtomicMarkableReference;
加上版本号之后,不仅需要比较内存地址的数值,还需要比较版本号是否相同;
「CAS一直自旋带来的性能损耗」,如果使用CAS尝试获取锁资源一直没有成功,导致CPU一直处于自旋状态,会引起性能损耗。
「只适用于对一个变量的操作」,如果需要对多个变量保证原子性操作,建议使用锁。
3.Java内存模型
Q:什么是Java内存模型?
「Java 内存模型」是一种规范,为了保证线程操作共享资源时的可见性。
JMM 定义了所有的共享变量资源都存储在主存中,而每个线程都有属于自己的本地内存,线程不能访问其它线程的本地内存。
线程之间必须通过主存进行数据的沟通交流。
JMM 通过控制「主存」和「本地内存」完成线程之间的数据交互,实现线程之间的可见性。
4.volatile
Q:什么是volatile?
被「volatile」关键字修饰的变量有两层含义,有序性、可见性。
Q:volatile的底层实现原理?
volatile 的「底层实现原理」是通过操作系统的内存屏障实现的,对于volatile的「写」操作,会加入写屏障,对于volatile的「读」操作,会加入读屏障。
「写屏障」保证对volatile修饰的变量的写操作,会立马同步到主存,并且对其它线程可见,写操作之前的指令不会重排序到写操作之后。
「读屏障」保证对volatile修饰的变量的读操作,总是会从主存中读取最新的数值,都操作之前的指令不会重排序到读操作之后。
5.Redis
Q:什么是Redis?你可以简单的介绍一下你对Redis的了解吗?
Redis 是基于 C语言,一种基于内存的NoSQL型数据库,速度极快,常作用于:缓存、消息队列、分布式锁。
Q:Redis和Memcached的区别?为什么不用Memcached呢?
共同点:
- 都是基于内存的数据库;
- 性能高;
- 都有过期策略;
不同点:
- Redis有多种数据类型,而Memcached只有key-value类型;
- Redis可以数据持久化,即使发生宕机或者挂机、停机,可以恢复数据,而Memcached只要停机了数据是完全基于内存的,会丢失数据;
- Redis支持原生的集群模式,Memcached不支持;
- Redis还可以使用事务、lua脚本语言、发布订阅模型;Memcached不支持;
Q:为什么Redis可以用来做缓存呢?
「高性能」,Redis是基于内存的,如果每次查找数据都是从 MySQL 中查找,需要从硬盘中读取数据到性能很慢。
如果将部分数据缓存在内存Redis中,去内存中查找数据就会很快。
「高并发」,Redis的QPS是MySQL的10倍,单机Redis的QPS可以达到10w。
Q:Redis的数据类型及应用场景,你可以介绍一下吗?
五种基本数据类型:
- String,存储token、json串、图片地址;计数自增自减;分布式锁;
- List,存储文章列表;消息队列;
- Hash,个人信息、商品详情等;
- Set,共同关注、点赞;
- Zset,排行榜等;
四种独特的类型:
- Bitmaps,签到打卡;
- HyperLogLog,百万千万级,统计网站UV;
- Geo,地理信息,滴滴打车,附近的人;
- Stream,消息队列;
Q:Redis的SDS数据结构你可以介绍一下吗?为什么不使用C语言的字符串呢?
「C语言字符串的坏处」:
- 获取字符串的长度,时间复杂度为O(N);
- 无法存储二进制数据;
- 可能存在缓冲区溢出;
「SDS」数据结构,有四个关键的属性:
- len,字符串长度;
- alloc,字符串的内存大小;
- flags,字符串类型;
- buf[],字符串数组;
解决了C语言字符串的三个问题。
总结
提示:这里对文章进行总结:
今天总算学习状态稍微好了点,希望明天再接再厉,明天需要完成:
- 组会汇报;
- Redis数据结构;
- 复习SE;
- 刷算法题;