浅谈 synchronized 和 volatile

一、锁

从细节上来说,锁分为 乐观锁、悲观锁

乐观锁适用于读多写少的场景,一般是通过 CAS 进行操作,因为不用加锁,所以性能上比悲观锁优秀太多

悲观锁适用于写多读少的场景,性能开销比较大。

1:乐观锁

阅读更多

Spring ContentNegotiation(内容协商)之原理篇(二)

简介

在了解这部分之前,你需要知道 Spring 都是通过 DispatcherServlet 来处理和分发请求的,如果不知道的话也不会影响到本文的阅读

在开启内容协商之后,URL 肯定是会变的,例如之前是 a/b,开启后则变成为 a/b.json 或者 a/b.xml

那么 Spring 首先第一步就需要解决如何将这个 url 映射到正确的 Controller 上的呢?

HandlerMapping

阅读更多

Spring ContentNegotiation(内容协商)之使用篇(一)

背景

随着业务系统的成熟,如果你的项目正好是公司的中台战略之一,但是下游系统的接收方式不统一,这一种情况在一些老的公司系统架构总经常出现,如果下游系统不方便兼容,那么就需要中台系统对外提供各种不同格式返回报文

内容协商

简单说就是服务提供方根据客户端所支持的格式来返回对应的报文,在 Spring 中,REST API 基本上都是以 json 格式进行返回,而如果需要一个接口即支持 json,又支持其他格式,开发和维护多套代码显然是不合理的,而 Spring 又恰好提供了该功能,那便是ContentNegotiation

在 Spring 中,决定一个数据是以 json、xml 还是 html 的方式返回有三种方式,分别如下:

阅读更多

聊一聊 SpringBoot 中的一些被忽视的注解

之前在老的项目中看到了一个比较有趣的现象

有一个需求是需要对返回的数据进行加解密的操作,部分老代码是直接硬编码在项目中,但是后来有人改了一版,称之为 1.0 版本

1.0 版本是通过切面配合注解进行处理,大致的处理流程是对返回的对象通过反射遍历字段,如果发现字段上有指定的注解,则进行加密操作,如果发现该字段是一个对象的话,则进行递归处理,直至结束

后来有一个需求是对返回的手机号、身份证信息只需要对中间的信息进行加密,两边不处理…其他的例如家庭地址、家庭成员全部加密为密文

拿到这个需求的时候,想改也挺简单,只需要增加一个新的注解,然后替换该切面扫描到的返回值进行替换注解就可以了

阅读更多

重温生产者和消费者模型

生产者和消费者模型,主要解决的是数据的同步问题,生产者将数据放置一个存储区域,然后消费者过来取数据。这种模式类似于一个中间件,可以使得生产者不需要关心消费者什么时候来拿数据,同时在这种模式下,还可以控制两边的处理速率,避免数据的丢失。

下面以 Java 为例,来写一个生产者和消费者模型。

当队列满了的时候,生产者自己进行阻塞。而当消费者发现队列为空,则将自己阻塞。

所以要实现这个生产者消费者模型,首先必须有以下条件:

  1. 生产者或者消费者必须支持可阻塞
  2. 在多线程的情况下,必须保证并发安全(即插入不能产生数据错误),取数据不可以重复取
阅读更多

快速写一个程序将JVM的堆或者栈打满

堆和栈

数据结构

首先「堆」或者「栈」在本质上其实是一个数据结构,简介如下:
「栈」既可以用链表来实现,又可以用数组来实现,用链表来实现的话,它是一个含有头指针和尾指针的一种数据结构,根据含有指针的不同,分为单链表和双向链表。
「堆」是一种类似于「完全二叉树」的数据结构

JVM中的堆和栈

在 JVM 中由于编译后的 class 文件都是一行行的指令,因此天然适合用「栈」这种数据结构,

阅读更多

Thread.sleep(0)-vs-Thread.yield()

简介

Thread.sleep(long)yield() 都表示的是让出当前线程的 CPU 时间片,两者在执行的时候,都不会去释放自己已经持有的锁。

多线程

在现代的处理器中,以 4核心CPU 为例,这表示在同一个时刻,只会有 4 个线程在并行执行,而在每一个核心内部,多个线程其实是顺序执行的,它们的执行顺序依赖于线程的调度算法。

线程调度算法

阅读更多

ThreadLocalMap 简单分析

ThreadLocal

在使用多线程的时候,如果需要保存一份线程自己私有的一部分变量,避免其他线程污染这个变量的话,一般都会自己手动 new 一个 ThreadLocal,如下代码:

1
2
ThreadLocal<String> threadLocal = new ThreadLocal<>();
threadLocal.set("test");

当需要在某一刻使用这个变量的时候,只需要手动调用下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
threadLocal.get();
```

## ThreadLocalMap
ThreadLocalMap 是 ThreadLocal 的一个静态内部类,每一个线程在创建的时候都会有这个 ThreadLocalMap 变量,它的作用就是存储每一个通过 `threadLocal.set()` 方法存入的值,本质上也是一个HashMap。

先看下它的一个内部类:
### Entry
不同于 WeakHashMap 是继承自 HashMap 的Entry,ThreadLocalMap 的Entry 则是自己的一个内部类。
```java
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
阅读更多

Springboot自定义@EnableXX注解

在SpringBoot中,经常可以看到许多以 @Enable 开头的注解,例如:@EnableAutoConfiguration@EnableAsync……,那么我们是否可以自己定义一个注解呢?

其实自定义注解最终都是利用到了 ImportBeanDefinitionRegistrar 这个类,通过手动的方式,将一个类注册成为 Bean,然后在进行一系列的操作,下面就来看下 ImportBeanDefinitionRegistrar

ImportBeanDefinitionRegistrar

这个类的代码如下:

可以看到这个类的结构很简单,就是一个方法,那么下面来看下这两个参数是什么意思。

阅读更多

Springboot的maven间接依赖

在项目中经常使用 maven 来管理项目,但是有时候对于 maven 的细节还是了解的不是很清楚,因此今天复习下。

maven项目

首先开始建立一个最简单的 maven 项目,其配置如下图:

可以看到最上面一行是 xml 的文件描述符,然后再是 project,在这里引入 xsd 文件。

XSD(XML Schemas Definition)XML Schema,描述了 xml 文档的结构,用于判断其是否符合 xml 的格式要求

阅读更多