some parameters that only one is not null valid

注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomValid {

}

@Documented
@Constraint(validatedBy = OnlyOneNotNullValidator.class)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface OnlyOneNotNull {

String message() default "only one filed should not be null";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};

String[] fieldNames();

}
阅读更多

时间格式 注解 验证

EnumValid.java

1
2
3
4
5
6
7
8
9
10
11
12
13

@Constraint(validatedBy = DateFormatValidator.class)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DateFormat {
String message() default "";

String pattern() default "yyyy-MM-dd HH:mm:ss";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}
阅读更多

枚举类型参数验证

EnumValid.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Documented
@Constraint(validatedBy = EnumValidator.class)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface EnumValid {

Class<? extends Enum<?>> enumClass();

String message() default "invalid enum item value.";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}
阅读更多

GC算法 垃圾收集器

概述

jvm 中,程序计数器、虚拟机栈、本地方法栈都是随线程而生随线程而灭,栈帧随着方法的进入和退出做入栈和出栈操作,实现了自动的内存清理。

因此,我们的内存垃圾回收主要集中于 **java 堆和方法区中**,在程序运行期间,这部分内存的分配和使用都是动态的.

对象存活判断

判断对象是否存活一般有两种方式:

引用计数:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。此方法简单,无法解决对象相互循环引用的问题。

可达性分析(Reachability Analysis):从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。不可达对象。

在Java语言中,GC Roots包括:

  • 虚拟机栈中引用的对象。
  • 方法区中类静态属性实体引用的对象。
  • 方法区中常量引用的对象。
  • 本地方法栈中JNI引用的对象。

垃圾收集算法

标记 -清除算法

“标记-清除”(Mark-Sweep)算法,如它的名字一样,算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。之所以说它是最基础的收集算法,是因为后续的收集算法都是基于这种思路并对其缺点进行改进而得到的。

它的主要缺点有两个:一个是效率问题,标记和清除过程的效率都不高;另外一个是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致,当程序在以后的运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

  1. Getting Started with the G1 Garbage Collector
  2. The Garbage First Garbage Collector
  3. 垃圾优先型垃圾回收器调优
  4. Java Hotspot G1 GC的一些关键技术
  5. 一步步图解G1
  6. 徹底解剖「G1GC」実装編
  7. Part 1: Introduction to the G1 Garbage Collector
  8. Collecting and reading G1 garbage collector logs - part 2

    参考文章

Compare-and-Swap

CAS是乐观锁的一种思想,它假设线程对资源的访问是没有冲突的,同时所有的线程执行都不需要等待,可以持续执行。如果有冲突的话,就用比较+交换的方式来检测冲突,有冲突就不断重试。

CAS的全称是Compare-and-Swap,也就是比较并交换,它包含了三个参数:V,A,B,V表示要读写的内存位置,A表示旧的预期值,B表示新值,当执行CAS时,只有当V的值等于预期值A时,才会把V的值改为B,这样的方式可以让多个线程同时去修改,但也会因为线程操作失败而不断重试,对CPU有一定程序上的开销。
img.png

参考文章

Java内存模型

JVM内存结构

Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途。

  • pc register, 栈,本地方法栈
  • 堆,方法区 (所有线程共享)
  • 运行时常量

Java内存模型

JVM的内存结构的图中,我们可以看到,其中Java堆和方法区的区域是多个线程共享的数据区域。也就是说,多个线程可能可以操作保存在堆或者方法区中的同一个数据。这也就是我们常说的“Java的线程间通过共享内存进行通信”。

Java内存模型是根据英文Java Memory Model(JMM)翻译过来的。其实JMM并不像JVM内存结构一样是真实存在的。他只是一个抽象的概念。JSR-133: Java Memory Model and Thread Specification中描述了,JMM是和多线程相关的,他描述了一组规则或规范,这个规范定义了一个线程对共享变量的写入时对另一个线程是可见的。

那么,简单总结下,Java的多线程之间是通过共享内存进行通信的,而由于采用共享内存进行通信,在通信过程中会存在一系列如可见性、原子性、顺序性等问题,而JMM就是围绕着多线程通信以及与其相关的一系列特性而建立的模型。JMM定义了一些语法集,这些语法集映射到Java语言中就是volatile、synchronized等关键字。

Java对象模型

Java是一种面向对象的语言,而Java对象在JVM中的存储也是有一定的结构的。而这个关于Java对象自身的存储模型称之为Java对象模型。

HotSpot虚拟机中,设计了一个OOP-Klass Model。OOP(Ordinary Object Pointer)指的是普通对象指针,而Klass用来描述对象实例的具体类型。

JVM内存结构,和Java虚拟机的运行时区域有关。
Java内存模型,和Java的并发编程有关。
Java对象模型,和Java对象在虚拟机中的表现形式有关。

JVM内存结构 VS Java内存模型 VS Java对象模型
再有人问你Java内存模型是什么,就把这篇文章发给他。
深入理解多线程(一)——Synchronized的实现原理

Java 内存模型

对JVM内存结构的描述中,我们知道了堆和方法区是线程共享的。而局部变量,方法定义参数和异常处理器参数就不会在线程之间共享,它们不会有内存可见性问题,
也不受内存模型的影响。

Java线程之间的通信由Java内存模型(本文简称为JMM)控制,JMM决定一个线程对共享变量的写入何时对另一个线程可见。
从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),
本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM的一个抽象概念,并不真实存在。
它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。

阅读更多

AtomicInteger&无锁对象引用:AtomicReference

AtomicInteger介绍

AtomicInteger是一个提供原子操作的Integer类,通过线程安全的方式操作加减。

AtomicInteger使用场景

AtomicInteger提供原子操作来进行Integer的使用,因此十分适合高并发情况下的使用。

1.作为多个线程同时使用的原子计数器。

2.在比较和交换操作中实现非阻塞算法。

AtomicInteger作为原子计数器

要将其用作计数器,AtomicInteger类提供了一些方法来原子地执行加减运算。

1
2
3
4
5
6
addAndGet():以原子方式将给定值添加到当前值,并在添加后返回新值。
getAndAdd():以原子方式将给定值添加到当前值并返回旧值。
crementAndGet():以原子方式将当前值增加1,并在增加之后返回新值。 它等效于++ i操作。
getAndIncrement():以原子方式递增当前值并返回旧值。 它等效于i ++操作。
decrementAndGet():以原子方式将当前值减1,并在减后返回新值。 它等效于i-操作。
getAndDecrement():以原子方式减少当前值并返回旧值。 它等效于– -i操作。

AtomicInteger源码部分讲解

阅读更多