爱分享 - java
type: channel
link: http://gxxblw.com/tag/java/
items: 并发编程-Java jdk中队列Queue的详解与应用
items: Java中基本数据类型与对应的包装类型介绍
items: Java中双等号比较运算"=="和"equals"方法的区别
items: Java中ThreadLocal简单学习使用
items: Java 书单：比较全的一篇
items: Spring Cache 缓存 Cacheable注解使用

并发编程-Java jdk中队列Queue的详解与应用
type: item
date: 2023-01-31T22:35:00+08:00
description: 一、什么是队列，队列有什么用？假设春运火车站只有一个售票窗口，但是买火车票的人非常多，如果大家一哄而上到窗口进行买票，估计售票员会发疯，因此聪明的人类发明了排队这种游戏规则，则先到先得的机制，在不断的发展过程中，排队的规则也慢慢完善，比如有些例外比如军人优先或者老弱病残优先则可以进行插队，通过这样的规则可以让面对人流高峰也可以平稳进行工作。这个规则运用到实际开发中也是如此，在程序中队列是一种特殊的线性表，遵循先入先出、后入后出的基本原则，一般来说，它只允许在队列的前端进行删除操作，而在队列的后端进行插入操作。但是java的某些队列运行在任何地方插入删除（如军人插队）在java中根据队列特性，队列可分为阻塞队列和非阻塞队列，有界队列和无界队列、单向链表队列和双向链表队列之分,二、阻塞/非阻塞队列2.1 阻塞队列入列(添加元素)时，如果元素数量超过队列总数，会进行等待（阻塞），待队列的中的元素出列后，元素数量未超过队列总数时，就会解除阻塞状态，进而可以继续入列；出列(删除元素)时，如果队列为空的情况下，也会进行等待（阻塞），待队列有值的时候即会解除阻塞状态，进而继续出列；阻塞队列优点 ：阻塞队列的好处是可以防止队列容器溢出；只要满了就会进行阻塞等待；也就不存在溢出的情况,只要是阻塞队列，都是线程安全的；实现类DelayQueue：一个支持延时获取元素的无界阻塞队列LinkedTransferQueue：一个由链表结构组成的无界阻塞队列。ArrayBlockingQueue：有界队列，阻塞式,初始化时必须指定队列大小，且不可改变；，底层由数组实现；SynchronousQueue：最多只能存储一个元素，每一个put操作必须等待一个take操作，否则不能继续添加元素PriorityBlockingQueue：一个带优先级的队列，而不是先进先出队列。元素按优先级顺序被移除，而且它也是无界的，也就是没有容量上限，虽然此队列逻辑上是无界的，但是由于资源被耗尽，所以试图执行添加操作可能会导致 OutOfMemoryError 错误；2.2 非阻塞队列不管出列还是入列，都不会进行阻塞，入列时，如果元素数量超过队列总数，则会抛出异常，出列时，如果队列为空，则取出空值；一般情况下，非阻塞式队列使用的比较少，一般都用阻塞式的对象比较多；阻塞和非阻塞队列在使用上的最大区别就是阻塞队列提供了以下2个方法：出队阻塞方法 ： take()入队阻塞方法 ： put()实现类ConcurrentLinkedQueue：单向链表结构的无界并发队列, 非阻塞队列，由CAS实现线程安全，内部基于节点实现ConcurrentLinkedDeque：双向链表结构的无界并发队列, 非阻塞队列，由CAS实现线程安全PriorityQueue: 内部基于数组实现，线程不安全的队列三、有界/无界队列有界和无界有界：有界限，大小长度受限制无界：无限大小，其实说是无限大小，其实是有界限的，只不过超过界限时就会进行扩容，就想ArrayList 一样，在内部动态扩容，最大值为Integer.MAX_VALUE四、单向/双向链表队列4.1 单向链表每个元素中除了元素本身之外，还存储一个指针，这个指针指向下一个元素；4.2 双向链表除了元素本身之外，还有两个指针，一个指针指向前一个元素的地址，另一个指针指向后一个元素的地址；四、 Java中队列的继承关系五、队列常用方法队列常用方法函数名函数介绍特殊说明add增加一个元索如果队列已满，则抛出一个IIIegaISlabEepeplian异常remove移除并返回队列头部的元素如果队列为空，则抛出一个NoSuchElementException异常element返回队列头部的元素如果队列为空，则抛出一个NoSuchElementException异常offer添加一个元素并返回true如果队列已满，则返回falsepoll移除并返问队列头部的元素如果队列为空，则返回nullpeek返回队列头部的元素如果队列为空，则返回nullput添加一个元素如果队列满，则阻塞take移除并返回队列头部的元素如果队列为空，则阻塞drainTo一次性取出队列所有元素)-PS知识点： remove、element、offer 、poll、peek 属于Queue接口的定义。六、代码示例假设现在需要售卖一趟车票共100张，并且有3个窗口开放售票，当有大量人购买时如何保障出票安全，我们使用ArrayBlockingQueue阻塞式有界队列来模拟常见代码。package com.queue; import cn.hutool.core.util.StrUtil; import java.util.concurrent.*; import java.util.concurr…

Java中基本数据类型与对应的包装类型介绍
type: item
date: 2023-01-16T22:47:00+08:00
description: 目录目录一. Java基本类型与包装类型介绍二 类型的自动装箱与拆箱举例说明一. Java基本类型与包装类型介绍Java中有8种基本数据类型，分别为：数字类型(6种) ：byte、short、int、long、float、double字符类型(1种) ：char布尔型(1种) ：boolean。这八种基本类型都有对应的包装类分别为：Byte、Short、Integer、Long、Float、DoubleCharacterBoolean基本类型位数字节默认值int3240short1620long6480Lbyte810char162'u0000'float3240fdouble6480dboolean1官方文档未明确定义，它依赖于 JVM 厂商的具体实现。逻辑上理解是占用 1位，但是实际中会考虑计算机高效存储因素。false二 类型的自动装箱与拆箱装箱与拆箱的含义：装箱：将基本类型用它们对应的引用类型包装起来；拆箱：将包装类型转换为基本数据类型；Java基本类型的包装类的大部分实现了常量池技术，即Byte,Short,Integer,Long,Character,Boolean；前面4种包装类默认创建了数值[-128，127]的相应类型的缓存数据，Character创建了数值在[0,127]范围的缓存数据，Boolean 直接返回True Or False。如果超出对应范围仍然会去创建新的对象。其中仅浮点数类型的包装类Float与Double 没有实现常量池技术。Boolean常量池public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); // 其中TRUE与FALSE为定义的静态常量 }CharacterCache 缓存常量池private static class CharacterCache { private CharacterCache(){} static final Character cache[] = new Character[127 + 1]; static { for (int i = 0; i < cache.length; i++) cache[i] = new Character((char)i); } }/** *此方法将始终缓存-128 到 127（包括端点）范围内的值，并可以缓存此范围之外的其他值。 */ public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) //如果在缓存范围值内 return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); // 不如不在范围内者使用new运算符创建一个堆内存返回新的对象 }举例说明例子1 Integer i1 = 33; Integer i2 = 33; System.out.println(i1 == i2);// 输出 true, 因为33在-128-127范围内使用的是缓存常量，即两个数值的内存地址一致 Integer i11 = 333; Integer i22 = 333; System.out.println(i11 == i22);// 输出 false // 超出范围，返回的都是new的新对象 Double i3 = 1.2; Double i4 = 1.2; System.out.println(i3 == i4);// 输出 false // Double未实现缓存常量池 例子2需要注意一旦使用new运算符创建对象，则将创建新的数据，不会使用缓存常量值，如以下Integer i1 = 40; Integer i2 = new Integer(40); System.out.println(i1==i2);//输出 falseInteger i1=40；Java 在编译的时候会直接将代码封装成 Integer i1=Integer.valueOf(40);，从而使用常量池中的对象。Integer i1 = new Integer(40);这种情况下会创建新的对象。例子3Integer i1 = 40; Integer i2 = 40; Integer i3 = 0; Integer i4 = new Integer(40); Integer i5 = new Integer(40); Integer i6 = new Integer(0); System.out.println("i1=i2 : " + (i1 == i2)); // tru…

Java中双等号比较运算"=="和"equals"方法的区别
type: item
date: 2023-01-16T22:13:00+08:00
description: 目录目录两个等于号 ==equals()比较两个等于号 ==它的作用是判断两个对象的内存地址是不是相等，即判断两个对象是不是同一个对象。基本数据类型比较的是值，引用数据类型==比较的是内存地址equals()比较它的作用也是判断两个对象是否相等，它不能用于比较基本数据类型的变量。 equals()方法存在于 Object 类中，而 Object 类是所有类的直接或间接父类。Object 类 equals() 方法：public boolean equals(Object obj) { return (this == obj); }equals() 方法存在两种使用情况：情况 1：类没有覆盖 equals() 方法, 则通过 equals() 比较该类的两个对象时，等价于通过“==”比较这两个对象。使用的默认是 Object 类 equals() 方法。情况 2：类覆盖 equals() 方法。一般覆盖 equals() 方法用来比对两个对象的 内容 相等；若它们的内容相等，则返回 true(即认为这两个对象相等),比如字符串的String类比较则是覆盖重写equals方法。实例代码：public class test1 { public static void main(String[] args) { String str1 = new String("test"); // a 为一个引用 String str2 = new String("test"); // b为另一个引用,对象的内容一样 String str3 = "test"; // 放在常量池中 String str4 = "test"; // 从常量池中查找 if (str3 == str3) // true System.out.println("aa==bb"); if (str1 == str2) // false，非同一对象 System.out.println("a==b"); if (str1.equals(str2)) // true System.out.println("equals比较内容相等"); if (42 == 42.0) { // true System.out.println("true"); } } }特别说明String 中的 equals 方法是被重写过的，因为 Object 的 equals 方法是比较的对象的内存地址，而 String 的 equals 方法比较的是对象的值。当创建 String 类型的对象时，虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象，如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。String 类 equals()的重写方法：public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }

Java中ThreadLocal简单学习使用
type: item
date: 2021-08-31T22:49:00+08:00
description: 文章目录索引文章目录索引ThreadLocal定义1、如何使用2.原理3.使用场景4.避免踩坑ThreadLocal定义该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物，因为访问某个变量（通过其 get 或 set 方法）的每个线程都有自己的局部变量，它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段，它们希望将状态与某一个线程（例如，用户 ID 或事务 ID）相关联。以上来源官方API。大概可以总结为两点：ThreadLocal提供get/set方法，可以访问属于当前线程的变量，也就是可以保证每个线程的变量不一样。ThreadLocal使用时通常定义为private static的。从字面意思理解，可能会将ThreadLocal认为是本地线程，其实ThreadLocal并不是线程，而是线程Thread的局部变量。1、如何使用首先，定义一个private static的ThreadLocal对象。private static ThreadLocal<String> threadLocal = new ThreadLocal<>();然后每个线程可以将当前线程需要存放在局部变量中，并且可以从中获取。public void setAndGet(String name) { threadLocal.set(name); String s = threadLocal.get(); }最后在使用完之后，需要将ThreadLocal中的值移除。public void remove() { threadLocal.remove(); }2.原理那么ThreadLocal是如何做到保证每个线程get出来的数据不一样的呢？我们通过源码来看一下。public void set(T value) { Thread t = Thread.currentThread(); // 通过当前线程获取出来一个ThreadLocalMap ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }我们发现在set方法中，会创建一个ThreadLocalMap，然后将要设置的值放在这个Map中，而当前这个ThreadLocal对象作为key；然后再将这个ThreadLocalMap赋值给Thread的threadLocals里。如果去看Thread类的代码会发现，在Thread类中存在两个变量threadLocals和inheritableThreadLocals，它们的类型就是ThreadLocal.ThreadLocalMap。通过下图可以看出Thread，ThreadLocal，ThreadLocalMap三者的关系。这时候我们再看看get()和remove()方法的代码。public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); } ThreadLocalMap getMap(Thread t) { return t.threadLocals; } public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }可以看出来，和我们上面图中的结构一样，get()方法就是从Thread中取出来ThreadLocalMap，然后通过ThreadLocal对象作为Key取出值；remove()方法则是取出ThreadLocalMap将ThreadLocal对应的数据移除。那么ThreadLocalMap到底是什么呢？是java.util.Map接口的子类吗？我们来看源码。static class ThreadLocalMap { static…

Java 书单：比较全的一篇
type: item
date: 2021-08-11T15:40:56+08:00
description: 健康《程序员健康指南》- 链接：https://pan.baidu.com/s/1hb8xQCE3TrEjazF5ZCe6-w ，提取码：h6fh本书是为程序员量身制作的健康指南，针对头痛、眼部疲劳、背部疼痛和手腕疼痛等常见的问题，简要介绍了其成因、测试方法，并列出了每天的行动计划，从运动、饮食等方面给出详细指导，帮助程序员在不改变工作方式的情况下轻松拥有健康。之所以把这个放到第一位，是因为许多健康问题都是知道的越早越好，这样才能更好地预防Java 基础《Head First Java（第二版）》- 链接：https://pan.baidu.com/s/17LNLb-1s_k9wR1kK__s1eQ ，提取码：v3ae《Java核心技术卷一（第十版）》- 链接：https://pan.baidu.com/s/1l-pDMOkR832ceA5q2CVZ7g ，提取码：v88g《Java编程思想（第四版）》 - 链接：https://pan.baidu.com/s/1NwOrkSadZuL64DH43_5rKA ，提取码：jgorJava 进阶偏实战，需要打好上面的基础《Java8实战》- 链接：https://pan.baidu.com/s/1P6RBXi5PzRm4zuKgUr14sg ，提取码：q3lo《Java 并发编程实战》- 链接：https://pan.baidu.com/s/1m6ts-HSu2SgFVRgJKKPl6Q ，提取码：i7nz《实战Java高并发程序设计（第2版） 》- 链接：https://pan.baidu.com/s/1tSPNtR1CNGea6gKfXnBklA ，提取码：dad3《Java性能权威指南》- 链接：https://pan.baidu.com/s/1OlHlJ4qyPHQe5QMB6qkLmw ，提取码：vwca《深入理解Java虚拟机：JVM高级特性与最佳实践（第3版）》- 链接：https://pan.baidu.com/s/1ZQi72jiqQzHlFhdkMqJtXg ，提取码：h7n7Java 优化下面主要讲解了Java开发常见的一些规范，使代码更加整洁高效《码出高效：Java开发手册》- 链接：https://pan.baidu.com/s/19sttAcC01G0wg1nqkfmprA ，提取码：zemp《Effective Java（第三版）》- 链接：https://pan.baidu.com/s/1RDaiVNViHvTVVunMkpFecg ，提取码：m9qe《嵩山版 Java 开发手册》- 链接：https://pan.baidu.com/s/1Rgh5tA_yPE-nV9MjPE572w ，提取码：62iw《代码整洁之道》《程序员修炼之道 从小工到专家》- 链接：https://pan.baidu.com/s/1lVoRCEr9NJR2I5rPneXK0g ，提取码：fxwe计算机《TCP-IP详解(卷一、二、三)》- 链接：https://pan.baidu.com/s/1D7luuYvEfTjaC7bh8Tm1Hg ，提取码：pmcj《深入理解计算机系统（原书第3版）》- 链接：https://pan.baidu.com/s/15F6MOyryXUI_l7DLoNbgiA ，提取码：7x0u算法《算法图解》- 链接：https://pan.baidu.com/s/1qbJAJbLInXo-rlPBGLOFUA ，提取码：k9nj《算法珠玑(Java版)》- 链接：https://pan.baidu.com/s/1EQj2sQk1Ys-EU8mwHho_MA ，提取码：7fxt《Leetcode 前 300 题算法题解析（Java）》- 链接：https://pan.baidu.com/s/1BGuMZW2ec4P_cyiv6sicww ，提取码：2jty设计模式《Head First 设计模式》- 链接：https://pan.baidu.com/s/1rxH5Ll38VpHl_j6ts6Q-oQ ，提取码：z6xg《Design-Pattern包教不包会(设计模式包教不包会)》- 链接：https://pan.baidu.com/s/1SDIsamZCv7JKY1zTuNLKtg ，提取码：81ci《设计模式 Java版本》- 链接：https://pan.baidu.com/s/1ikneBCgvAoIk5A-M6snIPg ，提取码：7b98《设计模式：可复用面向对象软件的基础》- 链接：https://pan.baidu.com/s/1CPJUAJp_oryQnKxWCbn8tA ，提取码：7qtiSpring 全家桶《Spring实战（第4…

Spring Cache 缓存 Cacheable注解使用
type: item
date: 2021-07-09T21:55:00+08:00
description: 篇我来向大家介绍一种兼容所有缓存中间件的方案，不论我们是使用 Redis 还是 Ehcache，都不需要关心如何操作 Redis 或者 Ehcache，这套方案统统帮你搞定。这套方案就是大名鼎鼎的 Spring Cache。什么？你没有听过，没关系，本篇带你一起探索。文章目录索引文章目录索引一、揭开 Spring Cache 的面纱1.1 现有缓存方案的痛点1.2 Spring Cache 介绍1.3 Spring Cache 有什么功效1.4 Spring Cache 的原理是什么？1.5 缓存注解二、使用缓存2.1 引入 Spring Cache 依赖2.2 配置使用哪种缓存2.3 测试缓存2.4 自定义配置类2.5 自定义 key2.6 自定义条件2.7 更新注解2.8 删除缓存注解三、 总结一、揭开 Spring Cache 的面纱1.1 现有缓存方案的痛点试想一种场景：用户 A 打开 APP，进入到了秒杀商品的详情页，那这个商品数据我们会先去数据库查询，然后返回给客户端。因为有大量用户短时间内进入到了详情页，所以可以把活动列表缓存起来，直接读缓存就可以了。那下次再查询商品时，直接去缓存查询就可以了。如果秒杀商品下架了，缓存的数据不会用到了，就把缓存删掉就可以了。上面几步看起来也没啥问题，但是放缓存，删除缓存这两步是需要我们去手动写代码实现的。有没有一种方式不用写操作缓存的代码？假如现在用的缓存中间件是 Redis，领导说要换成 Ehcache，操作缓存的代码是不是又得重新撸一遍？总结下上面场景的痛点：需要手写操作缓存代码，如添加缓存、更新缓存、删除缓存。切换缓存组件并不容易，或者说没有对缓存层进行抽象封装，依赖具体的缓存中间件。哪有没有一种方案可以帮助解决上面的两个痛点呢？这就是今天要介绍的 Spring Cache。1.2 Spring Cache 介绍Spring Cache 是 Spring 提供的一整套的缓存解决方案。虽然它本身并没有提供缓存的实现，但是它提供了一整套的接口和代码规范、配置、注解等，这样它就可以整合各种缓存方案了，比如 Redis、Ehcache，我们也就不用关心操作缓存的细节。Spring 3.1 开始定义了 org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 接口来统一不同的缓存技术，并支持使用注解来简化我们开发。Cache 接口它包含了缓存的各种操作方式，同时还提供了各种xxxCache缓存的实现，比如 RedisCache 针对 Redis，EhCacheCache 针对 EhCache，ConcurrentMapCache 针对 ConCurrentMap，具体有哪几种，后面实战中会介绍。1.3 Spring Cache 有什么功效每次调用某方法，而此方法又是带有缓存功能时，Spring 框架就会检查指定参数的那个方法是否已经被调用过，如果之前调用过，就从缓存中取之前调用的结果；如果没有调用过，则再调用一次这个方法，并缓存结果，然后再返回结果，那下次调用这个方法时，就可以直接从缓存中获取结果了。1.4 Spring Cache 的原理是什么？Spring Cache 主要是作用在类上或者方法上，对类中的方法的返回结果进行缓存。那么如何对方法增强，来实现缓存的功能？学过 Spring 的同学，肯定能一下子就反应过来，就是用 AOP（面向切面编程）。面向切面编程可以简单地理解为在类上或者方法前加一些说明，就是我们常说的注解。Spring Cache 的注解会帮忙在方法上创建一个切面（aspect），并触发缓存注解的切点（poinitcut），听起来太绕了，简单点说就是：Spring Cache 的注解会帮忙在调用方法之后，去缓存方法调用的最终结果，或者在方法调用之前拿缓存中的结果，或者删除缓存中的结果，这些读、写、删缓存的脏活都交给 Spring Cache 来做了，是不是很爽，再也不用自己去写缓存操作的逻辑了。1.5 缓存注解Spring 提供了四个注解来声明缓存规则。@Cacheable，@CachePut，@CacheEvict，@Caching。大家先有个概念，后面我们再来看怎么使用这些缓存注解。二、使用缓存2.1 引入 Spring Cache 依赖在 pom 文件中引入 spring cache 依赖，如下所示： org.springframework.boot spring-boot-starter-cache 2.2 配置使用哪种缓存Spring Cache 支持很多缓存中间件作为框架中的缓存，总共有 9 种选择：caffeine：Caffeine 是一种高性能的缓存库，基于 G…