flbu blog

记录学习历程


  • 首页

  • 分类

  • 归档

  • 标签

  • 关于

  • 搜索

Golang-Slice切片

发表于 2022-06-29 | 分类于 Golang

Slice是Go语言提供的一种常用的动态数据结构,相比数组,其长度并不固定,当我们向切片中添加元素时,如果容量不足就会自动扩容。

可以通过三种方式声明一个切片:

  1. 利用下标获取数组或切片的一部分
  2. 使用字面量初始化新的切片
  3. 使用关键字make创建切片
1
2
3
4
5
6
//1
mySlice := slice[1:3]
//2
mySlice := []int{1,2,3}
//3
mySlice := make([]int,0,3)

切片在编译期间生成的类型只会包含元素类型,如int、interface{}等。

阅读全文 »

Golang sync.Mutex互斥锁原理解析

发表于 2022-05-18 | 分类于 Golang

Go sync.Mutex互斥锁原理解析

RocketMQ原理学习

发表于 2022-05-17 | 分类于 消息队列

消息队列学习笔记–RocketMQ

消息队列的优缺点

优点

异步

对于实时性不是很高的业务,如积分增减、发送短信等非核心流程,可以放到消息队列中去,提升整个链路的响应时间。

削峰填谷

对于秒杀等短时间大流量场景,可以将请求短暂的在消息队列中堆积,平滑的消费请求。

解耦

MQ可以实现服务的高内聚、低耦合,通过发布订阅模型实现系统/模块间的解耦。

缺点

系统可用性降低

MQ相当于一个依赖组件,一旦出问题会导致系统不可用。

系统复杂度提高

引入MQ如何保证消息不重复消费?如何处理消息丢失?如何保证消息的顺序消费?

数据一致性问题

生产者消费者事务执行结果不一致造成的数据不一致问题。

阅读全文 »

秒杀系统设计

发表于 2021-11-04 | 分类于 系统设计

秒杀系统设计

秒杀系统是一种应用广泛的高并发读写场景,秒杀就是在同一个时刻有大量的请求争抢购买同一个商品并完成交易的过程,对高性能、一致性、高可用要求较高,本文主要记录个人学习秒杀系统设计的收获与思考。

秒杀系统主要就是解决两个问题,一个高并发读,一个高并发写。并发读的优化思路就是尽量减少用户到服务端来读数据,或者读更少的数据;并发写的优化思路也是一样,同时还需要针对系统设计一些保护措施和兜底方案。从架构上就是要保证用户请求的数据尽量少、请求数尽量少、路径尽量短、依赖尽量少、避免单点。

  • 高性能。秒杀设计大量的读写操作,对性能要求极高。可以从数据的动静分离方案、热点的发现与隔离、请求的削峰与分层过滤、服务的优化等角度考虑。
  • 一致性。一致性主要体现在秒杀场景中的库存控制方面,既不能多卖也不能少卖。
  • 高可用。高可用主要是保证系统在异常情况时的可用性和正确性,需要设计异常处理和兜底方案。
阅读全文 »

ConcurrentHashMap源码学习

发表于 2020-09-13 | 分类于 源码学习

不安全的HashMap

总所周知,HashMap是非线程安全的,体现在rehash时的死循环,使用迭代器时的fast-fail和多线程环境下put操作出现丢失数据等。

虽然JDK也提供了一个安全版本的HashMap:Collections.SynchronizedMap,但因为其使用的是全局锁,并发性能较差。

因此,juc包下提供了线程安全且锁粒度较小的ConcurrentHashMap。

ConcurrentHashMap的结构与实现原理

ConcurrentHashMap在JDK1.7和JDK1.8中有者不同的实现。

阅读全文 »

Java多线程-锁

发表于 2020-09-10 | 分类于 Java多线程

Java中的锁

本篇文章主要介绍juc包下与锁相关的API和组件,包括Lock接口、AQS抽象队列同步器、重入锁、读写锁和Condition接口。

Lock接口

锁是用来控制多个线程访问资源的方式,除了synchronized之外,juc包下还提供了Lock接口来实现锁功能。其提供了与synchronized类似的同步功能,但需要显示的获取、释放锁,并且提供了更加强大的功能,如可中断的获取锁和超时获取锁等。

Lock接口提供了synchronized关键字不具备的特性:

特性 描述
尝试非阻塞的获取锁 当前线程尝试获取锁,如果锁这一时刻没有被其他线程获取到,则成功获取并持有锁
可中断的获取锁 获取到锁的线程能响应中断,拥有锁的线程被中断时,会抛出中断异常并释放锁
超时获取锁 在指定时间内获取锁,如果超时仍未获取锁,则返回

Lock接口的默认实现类为ReentrantLock,部分API如下:

void lock() 获取锁,调用该方法的线程尝试获取锁,获取成功后返回
void lockInterruptibly() throws InterruptedException 可中断的获取锁
boolean tryLock() 尝试非阻塞的获取锁,调用此方法后立即返回
boolean tryLock(long var1, TimeUnit var3) throws InterruptedException 超时获取锁,有三种可能会返回:超时、成功获取锁、被中断
void unlock() 释放锁
Condition newCondition() 获取等待通知组件,该组件和当前的锁绑定,只有获取了锁才能调用此方法,并且调用后释放锁
阅读全文 »

JVM类加载机制

发表于 2020-09-08 | 分类于 Java

JVM类加载机制

Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转化解析和初始化,最终形成可被虚拟机直接使用的Java类型,这个过程就叫虚拟机的类加载机制。Java中的加载、连接和初始化都是在运行期间完成的。类是在第一次使用时动态加载的,而不是一次性加载所有类。

阅读全文 »

JVM 垃圾收集器与内存分配策略

发表于 2020-09-04 | 分类于 Java

JVM 垃圾收集器与内存分配策略

Java是自动内存管理的,但了解相关的内存分配与回收机制仍然很重要。

在Java运行时数据区域中,程序计数器、虚拟机栈和本地方法栈都随着线程创建而创建,随着线程消亡而消亡,栈中的栈帧也随着方法的进入和退出而入栈和出栈,这部分的内存回收在编译后就是确定的。而堆和方法区中则有明显的不确定性,只有在运行时才能确定,内存的分配和回收都是动态的。通常意义上的垃圾回收都是指的对堆和方法区的回收。

阅读全文 »

Java内存区域

发表于 2020-07-21 | 分类于 Java

Java内存区域

与C++不同,在虚拟机自动内存管理机制下,对象不需要手动的delete/free,不容易出现内存泄露和内存溢出。但了解Java运行时数据区域仍然非常重要。

运行时数据区域

Java虚拟机在执行程序时会把内存分为若干个不同的数据区域,每个数据区域都有各自的用途以及创建和销毁的时间,有的区域随着虚拟机进程的启动而一直存在,有的区域则是依赖用户线程的启动和结束而建立和销毁。

JDK1.8之前:

图源JavaGuide

JDK1.8:

图源JavaGuide

其中,堆、方法区和直接内存(非运行时数据区)是线程共享的,程序计数器、虚拟机栈和本地方法栈是线程私有的。

阅读全文 »

Java泛型

发表于 2020-07-12 | 分类于 Java

Java泛型

泛型的意思就是参数化类型。在没有引入泛型机制前,需要针对不同的数据类型重复编写相同的代码,而引入泛型后就可以将数据类型与代码逻辑分离开,提高了程序的简洁性和可读性,同时也提供了编译时的类型转换安全检测功能。

泛型可以将类型参数化,参数一旦确定,如果类型不匹配,就无法通过编译。

阅读全文 »
123<i class="fa fa-angle-right"></i>

flbu

flbu的技术博客

29 日志
8 分类
23 标签
RSS
GitHub E-Mail
0%
© 2022 flbu
本站总访问量次