Java并发编程-原子操作类概览
参考文献
原子操作类
由于变量类型的关系,在J.U.C中提供了12个原子操作的类.这12个类可以分为四大类:
基本类型:
AtomicBoolean: 原子更新布尔类型
AtomicInteger: 原子更新整型
AtomicLong: 原子更新长整型
数组类型:
AtomicIntegerArray: 原子更新整型数组里的元素
AtomicLongArray: 原子更新长整型数组里的元素
AtomicReferenceArray: 原子更新引用类型数组里的元素
引用类型:
AtomicReference: 原子更新引用类型
AtomicReferenceFieldUpdater: 原子更新引用类型里的字段
AtomicMarkableReference: 原子更新带有标记位的引用类型,可以原子更新一个布尔类型的标记位和引用类型.
字段更新:
AtomicIntegerFieldUpdater: 原子更新整型的字段的更新器
AtomicLongFieldUpdater: 原子更新长整型字段的更新器
AotmicStampedReference: 原子 ...
Java基础-SPI机制
参考文献
Java SPI 机制详解
SPI机制
JDK SPI(Service Provider Interface)机制是一种基于接口的服务发现机制,它允许应用程序在运行时动态地查找和加载实现某个接口的服务提供者.
在每次类加载的时候会先去找到 class 相对目录下的 META-INF 文件夹下的 services 文件夹下的文件,将这个文件夹下面的所有文件先加载到内存中,然后根据这些文件的文件名和里面的文件内容找到相应接口的具体实现类,找到实现类后就可以通过反射去生成对应的对象,保存在一个 list 列表里面,所以可以通过迭代或者遍历的方式拿到对应的实例对象,生成不同的实现.
JDK SPI 机制的基本原理如下:
定义接口: 定义一个接口,其实现类将作为服务提供者.
配置文件: 在 META-INF/services目录下创建一个以接口全限定名命名的文本文件,该文件的内容是实现该接口的服务提供者的全限定名.
文件名一定要是接口的全类名,然后里面的内容一定要是实现类的全类名,实现类可以有多个,直接换行就好了,多个实现类的时候,会一个一个的迭代加载.
服务加 ...
I/O模型
参考文献
6.2 I/O Models
小林coding-什么是零拷贝?
Netty-零拷贝
Netty零拷贝机制
Zero Copy I: User-Mode Perspective
I/O读写的基本原理
为了避免用户进程直接操作内核,保证内核安全,操作系统将内存(虚拟内存)划分为两个部分:
内核空间(Kernel-Space)
用户空间(User-Space)
针对Linux操作系统而言,将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为内核空间,而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为用户空间
I/O 请求可以分为两个阶段,分别为调用阶段和执行阶段.
第一个阶段为I/O 调用阶段,即用户进程向内核发起系统调用.
第二个阶段为I/O 执行阶段.此时,内核等待 I/O 请求处理完成返回.
该阶段分为两个过程:首先等待数据就绪,并写入内核缓冲区;
随后将内核缓冲区数据拷贝至用户态缓冲区.
在Linux系统中,内核模块运行在内核空间,对应的进程处于内核态;用户 ...
Java并发编程-面试题(一)
参考文献
Java中线程的实现方式?
继承Thread类,重写run方法
实现Runnable接口,重写run方法
实现Callable接口,重写call方法,配合FutureTask
Callable一般用于有返回结果的非阻塞的执行方法
同步非阻塞
线程的状态
NEW
RUNNABLE
READY
RUNNING
WAITING
TIMED_WAITING
BLOCKED
TERMINATED
并发编程的三大特性
原子性
问题存在的原因: 分时复用机制引起
使用synchroinzed和Lock接口实现的锁
使用CAS
有序性
问题存在的原因: 重排序引起
使用volatile
使用synchroinzed和Lock接口实现的锁
Happens-Before
可见性
问题存在的原因: CPU缓存引起
使用volatile
使用synchroinzed和Lock接口实现的锁
使用final
Happens-Before原则
程序次序规则
管程锁定规则
volatile变量规则
线程启动规则
线程终止规则
线程中断规则
对象终结规则
Java锁的分 ...
JVM-Java语法糖
参考文献
不了解这12个语法糖,别说你会Java!
语法糖
语法糖的存在主要是方便开发人员使用,Java虚拟机并不支持这些语法糖。这些语法糖在编译阶段就会被还原成简单的基础语法结构,这个过程就是解语法糖
Java支持的语法糖
switch 支持 String 与枚举
对于编译器来说,switch中其实只能使用整型,任何类型的比较都要转换成整型。比如byte。short,char(ackii码是整型)以及int
泛型
通常情况下,一个编译器处理泛型有两种方式:Code specialization和Code sharing。
C++和C#是使用Code specialization的处理机制,而Java使用的是Code sharing的机制。
Code sharing方式为每个泛型类型创建唯一的字节码表示,并且将该泛型类型的实例都映射到这个唯一的字节码表示上。将多种泛型类形实例映射到唯一的字节码表示是通过类型擦除(type erasue)实现的。
也就是说,对于Java虚拟机来说,他根本不认识Map<String, String> map这样的语法。需要在编译阶 ...
Java并发编程(十三)-累加器
参考文献
累加器
AtomicLong :这是最基本的累加器,支持单个long类型的原子性操作.适用于低并发场景或单线程环境.
LongAdder :相比于AtomicLong ,LongAdder 在高并发环境中的性能更好,因为它使用了分段锁来避免多个线程同时竞争一个变量的情况.适用于高并发场景下的计数器或统计器.
DoubleAdder :与LongAdder 类似,但支持double类型的原子性操作.适用于需要累加double类型数据的高并发场景.
LongAccumulator :支持任意函数的原子性操作,可以自定义累加函数.适用于需要累加的场景比较复杂,需要自定义累加函数的情况.
DoubleAccumulator :与LongAccumulator 类似,但支持double类型的原子性操作.
这些累加器在多线程环境下都可以保证线程安全,可以用于实现高性能的计数器、统计器等场景.选择哪种累加器要根据具体的场景和需求来确定.
如果需要进行高并发的累加操作,可以选择LongAdder 或DoubleAdder ;
如果需要自定义累加函数,可以选择L ...
Java并发编程-Fork/Join
参考文献
JUC线程池: Fork/Join框架详解
线程池ForkJoinPool简介
Fork/Join
Fork/Join框架是Java并发工具包中的一种可以将一个大任务拆分为很多小任务来异步执行的工具,自JDK1.7引入。
ForkJoinPool是ThreadPoolExecutor线程池的一种补充,是对计算密集型场景的加强
Fork/Join组成
任务对象: ForkJoinTask (包括RecursiveTask、RecursiveAction 和 CountedCompleter)
ForkJoinPool只接收ForkJoinTask 任务(在实际使用中,也可以接收 Runnable/Callable 任务,但在真正运行时,也会把这些任务封装成 ForkJoinTask 类型的任务)
RecursiveTask是ForkJoinTask的子类,是一个可以递归执行的 ForkJoinTask
RecursiveAction 是一个无返回值的 RecursiveTask,CountedCompleter 在任务完成执行后会触发执行一个自定义的钩子函数。
...
Java并发编程-FutureTask
参考文献
JUC线程池: FutureTask详解
FutrueTask
FutureTask为Future提供了基础实现,如获取任务执行结果(get)和取消任务(cancel)等.如果任务尚未完成,获取任务执行结果时将会阻塞.一旦执行结束,任务就不能被重启或取消(除非使用runAndReset执行计算).FutureTask 常用来封装 Callable 和 Runnable,也可以作为一个任务提交到线程池中执行.除了作为一个独立的类之外,此类也提供了一些功能性函数供我们创建自定义 task 类使用.FutureTask 的线程安全由CAS来保证.
Callable接口
123456789public interface Callable<V> { /** * Computes a result, or throws an exception if unable to do so. * * @return computed result * @throws Exception if unable to compute ...
Java并发编程(十四)-CompletableFuture
参考文献
Java8实战
CompletableFuture原理与实践-外卖商家端API的异步化
Future
通常只需要使用将耗时的操作封装在一个Callable对象中,再将它提交给ExecutorService
1234567891011121314151617public class FutureTest { public static void main(String[] args) { ExecutorService executor = Executors.newCachedThreadPool(); Future<Double> future = executor.submit(new Callable<Double>() { @Override public Double call() throws Exception { return doSomeLongComputation(); ...
Java集合-LinkedList
参考文献
LinkedList-JDK8
属性
123456789101112131415161718// 元素个数transient int size = 0;/** * 链表首节点 * Pointer to first node. * Invariant: (first == null && last == null) || * (first.prev == null && first.item != null) */transient Node<E> first;/** * 链表尾节点 * Pointer to last node. * Invariant: (first == null && last == null) || * (last.next == null && last.item != null) */transient Node<E> last;
节点类
1234567891011private static class Node& ...