Java相关
文章平均质量分 88
Java相关的一些知识。
程序员资料站
目前在一线互联网大厂,乐于给大家传播分享各种资料,交个朋友。
展开
-
从两道题来认识“事务的传播行为”
前言我们今天来学习关于事务的传播行为的知识。题目一题目如下:某个复杂的计算逻辑,由若干个子流程处理 + 主流程处理共同完成。业务要求是 :1)子流程处理互相独立,即其中一个发生错误事务回滚,不影响其他子流程的处理;2)主流程处理失败,事务回滚时,所有的子流程也要跟着回滚。思考鄙人苦苦思索良久,绞尽脑汁,穷尽我以前所学知识,憋出了如下的答案:class A { @Transactional public void methodA() {原创 2022-01-24 16:39:47 · 373 阅读 · 0 评论 -
Lucene应用实战(四)——Lucene搜索的两种方式
前言本文我们来对Lucene具体如何进行数据的搜索,进行详细的介绍。环境准备我们直接使用在 Lucene应用实战(二)——Field域的使用及索引库的维护 中的应用代码案例。因为索引和存储两者是分开的,对于某一个字段我们可以建立索引,但是不存储,我们依然可以对此字段进行搜索,但是因为我们没有存储,所以我们搜索出来的结果中不显示此字段的内容。本文为了结果的展示明显,我们将“desc“属性进行索引并且存储。搜索结果TopDocs类Lucene搜索结果可通过TopDocs遍历,TopDocs类提供了原创 2022-01-24 13:52:13 · 2089 阅读 · 0 评论 -
Lucene应用实战(三)——分词器的使用
前言前面几篇文章我们对Lucene中索引的创建等相关知识进行了初步的学习。接下来思考一个问题,我们创建的索引,是不是符合我们搜索要求的索引呢?平日里我们搜索东西的时候,输入某个关键词,有时候能搜出来,有时候搜别的关键词就搜不出来。用户输入的关键词和我们存储的索引之间会有一个匹配的过程,如果能匹配的上,那么就返回相应结果。索引创建是很关键的一环,而分词又是索引创建的核心,直接影响到索引的质量。接下来我们来从分词入手,详细拆解索引创建过程中分词的流程。分词的相关概念分词器:采集到的数据会存储到D原创 2022-01-24 13:51:28 · 1227 阅读 · 0 评论 -
Lucene应用实战(二)——Field域的使用及索引库的维护
Field域的使用及索引库的维护前言在前面我们对Lucene的使用进行了简单的demo实战,本文我们详细来说明下Lucene中的Field域的使用及索引库维护的相关操作。Fileld域的使用简介Lucene存储对象是以Document为存储单元,对象中相关的属性值则存放到Field中。Field是文档中的域,包括Field名和Field值两部分,一个文档可以包括多个Field,Document只是Field的一个承载体,Field值即为要索引的内容,也是要搜索的内容。Field有三大属性:原创 2022-01-24 13:50:45 · 511 阅读 · 0 评论 -
Lucene应用实战(一)——索引创建与搜索
Lucene简介Lucene是非常优秀的成熟的开源的免费的纯java语言的全文索引检索工具包。Lucene是一个高性能、可伸缩的信息搜索(IR)库。 Information Retrieval (IR) library.它可以为你的应用程序添加索引和搜索能力。Lucene是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。由Apache软件基金会支持和提供,Lucene提供了一个简单却强大的应用程序接口,能够做全文索引和搜索。原创 2022-01-24 13:49:04 · 2582 阅读 · 0 评论 -
都啥年头了,还问这种面试题
两道经典面试题灵魂拷问,我hold不住了原创 2022-01-22 19:46:09 · 500 阅读 · 0 评论 -
面试官:来说一说缓存雪崩、缓存穿透、缓存击穿的区别?我整个人都懵了
前言本文我们整理总结下Redis使用过程中一些常见的问题,并研究如何解决。缓存穿透一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。简介缓存穿透是指在高并发下查询key不存在的数据,会穿过缓存查询数据库。导致数据库压力过大而宕机 。解决方案解决方案:对查询结果为空的情况也进行缓存,缓存时间(ttl)设置短一点,或者该key对应的数据insert了之后清理缓存。存在的问题:缓存太多空值占用了更多的空间使用布隆过滤器。在缓存之前原创 2022-01-20 19:37:46 · 1967 阅读 · 2 评论 -
缓存“延时双删”真的有必要吗?我觉得没有
第一次清空缓存后,更新数据库前的这段时间内,其他事务查询了数据库的数据,第二次清空缓存后,刚才查询数据库 的那个线程又更新了缓存,此时又会将旧数据更新到缓存原创 2022-01-19 13:37:42 · 6018 阅读 · 1 评论 -
大厂面试十大真题(附有详细解答)
大厂面试十大真题,并附有详细解答,供大家学习,文末有额外大礼包资料及内推哦。原创 2022-01-18 13:59:53 · 953 阅读 · 0 评论 -
学会了伪共享问题解决方案,又能涨薪了
前言学习的过程中遇到了一个名词——“伪共享”,出于对知识的兴趣,上网查阅了一些博文,研究了“伪共享”的问题,写此文章总结记录。要很好的理解伪共享问题,我们要先从CPU的缓存开始说起。CPU缓存架构CPU 是计算机的心脏,所有运算和程序最终都要由它来执行。主内存(RAM)是数据存放的地方,CPU 和主内存之间有好几级缓存,因为即使直接访问主内存也是非常慢的。如果对一块数据做相同的运算多次,那么在执行运算的时候把它加载到离 CPU 很近的地方就有意义了,比如一个循环计数,你不想每次循环都跑到主内存原创 2022-01-17 13:50:44 · 275 阅读 · 1 评论 -
java对象分配过程及堆溢出测试
JVM设计者不仅需要考虑到内存如何分配,在哪里分配等问题,并且由于内存分配算法与内存回收算法密切相关,因此还需要考虑GC执行完内存回收后是否存在空间中间产生内存碎片。原创 2022-01-15 19:40:11 · 261 阅读 · 0 评论 -
java中“堆”的相关参数demo设置
堆大小 = 新生代 + 老年代。其中,堆的大小可以通过参数 –Xms、-Xmx 来指定。1)年轻代(Young Gen):年轻代主要存放新创建的对象,内存大小相对会比较小,垃圾回收会比较频繁。年轻代分成1个Eden Space和2个Survivor Space(from 和to)。2)年老代(Tenured Gen):年老代主要存放JVM认为生命周期比较长的对象(经过几次的Young Gen的垃圾回收后仍然存在),内存大小相对会比较大,垃圾回收也相对没有那么频繁。原创 2022-01-15 19:34:39 · 282 阅读 · 0 评论 -
GC日志分析实战,你了解吗?
前言本节我们来通过代码实战来看下GC日志的一些信息。代码示例我们看以下代码:package com.test;public class TestGCLog01 { private static final int _1MB = 1024*1024; /** * VM参数: * -Xms20M -Xmx20M -Xmn10M -XX:+UseParallelGC -XX:+PrintGCDetails -XX:SurvivorRatio=8 */原创 2022-01-15 13:51:33 · 104 阅读 · 0 评论 -
RabbitMQ实战(一)——RabbitMQ安装
RabbitMQ 简介RabbitMQ,俗称“兔子MQ”(可见其轻巧,敏捷),是目前非常热门的一款开源消息中间件,不管是互联网行业还是传统行业都广泛使用(最早是为了解决电信行业系统之间的可靠通信而设计)。RabbitMQ的特点如下:高可靠性、易扩展、高可用、功能丰富等支持大多数(甚至冷门)的编程语言客户端。RabbitMQ遵循AMQP协议,自身采用Erlang(一种由爱立信开发的通用面向并发编程的语言)编写。RabbitMQ也支持MQTT等其他协议。本文主要来介绍RabbitMQ的安装步原创 2022-01-15 13:47:49 · 165 阅读 · 0 评论 -
JVM如何判断一个对象是否存活?
前言在 深入浅出Java虚拟机(三)——初识JVM的垃圾回收机制 中我们介绍了如何判断对象已死的两种算法,分别是引用计数法和可达性分析法。本文我们再来详细说明一下JVM中判断对象是否、存活的相关细节。finalize()方法的执行条件即使在可达性分析算法中判定为不可达的对象, 也不是“非死不可”的, 这时候它们暂时还处于“缓刑”阶段, 要真正宣告一个对象死亡, 至少要经历两次标记过程:第一次标记:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链, 那它将会被第一次标记, 随后进原创 2022-01-15 10:30:00 · 613 阅读 · 0 评论 -
手把手教你如何自定义一个类加载器
前言前面 认识类加载器及双亲委派模型/ 中我们认识了类加载器,本文我们来自定义一个类加载器。为什么需要自定义类加载器?既然JDK已经有类加载器了,为什么还需要自定义类加载器呢?大概有以下几个原因:隔离加载类模块隔离,将类加载到不同的应用程序中。比如Tomcat这类web应用服务器,内部定义了好几种类加载器,用于隔离web应用服务器上不同的应用程序。扩展加载源 还可以从数据库、网络或其他终端上加载类防止源码泄露 Java代码容易被编译和篡改,可以进原创 2022-01-14 14:12:27 · 3364 阅读 · 1 评论 -
认识类加载器及双亲委派模型
类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。>注意:JVM主要在程序第一次主动使用类的时候,才会去加载该类,也就是说,JVM并不是在一开始就把一个>程序就所有的类都加载到内存中,而是到不得不用的时候才把它加载进来,而且只加载一次。原创 2022-01-14 14:09:41 · 301 阅读 · 0 评论 -
JVM常用指令实战(值得收藏即用即查)
前言本文我们来学习下JVM中的一些常用的指令。jps介绍jps 是(java process Status Tool), Java版的ps命令,查看java进程及其相关的信息,如果你想找到一个java进程的pid,那可以用jps命令替代linux中的ps命令了,简单而方便。命令格式:jps [options] [hostid]options参数解释:-l : 显示进程id,显示主类全名或jar路径-q : 显示进程id-m : 显示进程id, 显示JVM启动时传递给main()原创 2022-01-14 13:56:49 · 691 阅读 · 0 评论 -
JVM中类加载的过程详解
类从被加载到虚拟机内存中开始,到卸载出内存,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initiallization)、使用(Using)和卸载(Unloading)这7个阶段。其中验证、准备、解析3个部分统称为连接(Linking)原创 2022-01-13 19:10:32 · 600 阅读 · 0 评论 -
Java虚拟机栈的出栈入栈流程及栈内存大小设置
Java虚拟机栈(Java Virtual Machine Stacks)是线程私有的,即生命周期和线程相同。Java虚拟机栈和线程同时创建,用于存储栈帧。每个方法在执行时都会创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直到执行完成的过程就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。原创 2022-01-13 19:07:52 · 2590 阅读 · 2 评论 -
Java虚拟机(三)——初识JVM的垃圾回收机制
前言对于程序计数器、虚拟机栈、本地方法栈这三个部分而言,其生命周期与相关线程有关,随线程而生,随线程而灭。并且这三个区域的内存分配与回收具有确定性,因为当方法结束或者线程结束时,内存就自然跟着线程回收了。因此本篇文章所讲的有关内存分配和回收关注的是Java堆与方法区这两个区域。如何判断对象已死?1. 引用计数法简介给对象增加一个引用计数器,每当有一个地方引用它时,计数器就+1;当引用失效时,计数器就-1;任何时刻计数器为0的对象就是不能再被使用的,即对象已“死”。引用计数法实现简单,判定效率也比原创 2022-01-12 19:39:21 · 312 阅读 · 0 评论 -
深入浅出Java虚拟机(二)——Java内存模型
前言我们从一个问题入手来进行对JVM的深入理解。JVM的内存区域是怎么高效划分的?为什么要问到 JVM 的内存区域划分呢?因为 Java 引以为豪的就是它的自动内存管理机制。相比于 C++的手动内存管理、复杂难以理解的指针等,Java 程序写起来就方便的多。然而这种呼之即来挥之即去的内存申请和释放方式,自然也有它的代价。为了管理这些快速的内存申请释放操作,就必须引入一个池子来延迟这些内存区域的回收操作。我们常说的内存回收,就是针对这个池子的操作。我们把上面说的这个池子,叫作堆,可以暂时把它看成一个原创 2022-01-12 19:37:55 · 294 阅读 · 0 评论 -
深入浅出Java虚拟机(一)——初识JVM
什么是JVMJVM 全称 Java Virtual Machine,也就是我们耳熟能详的 Java 虚拟机。它能识别 .class后缀的文件,并且能够解析它的指令,最终调用操作系统上的函数,完成我们想要的操作。一般情况下,使用 C++ 开发的程序,编译成二进制文件后,就可以直接执行了,操作系统能够识别它;但是 Java 程序不一样,使用 javac 编译成 .class 文件之后,还需要使用 Java 命令去主动执行它,操作系统并不认识这些 .class 文件。Java 程序和我们通常使用的 C++原创 2022-01-12 19:34:21 · 318 阅读 · 0 评论 -
java并发编程(三十八)——“死锁“的发生及修复策略
前言锁是我们之前常使用的并发工具,但有时候也会有一些问题,比如死锁。本文我们来了解下死锁相关的知识。简介死锁一定发生在并发场景中。我们为了保证线程安全,有时会给程序使用各种能保证并发安全的工具,尤其是锁,但是如果在使用过程中处理不得当,就有可能会导致发生死锁的情况。死锁是一种状态,当两个(或多个)线程(或进程)相互持有对方所需要的资源,却又都不主动释放自己手中所持有的资源,导致大家都获取不到自己想要的资源,所有相关的线程(或进程)都无法继续往下执行,在未改变这种状态之前都不能向前推进,我们就把这种状原创 2022-01-12 19:31:15 · 289 阅读 · 0 评论 -
java并发编程(三十七)——什么是自旋锁?
“自旋”可以理解为“自我旋转”,这里的“旋转”指“循环”,比如 while 循环或者 for 循环。“自旋”就是自己在这里不停地循环,直到目标达成。而不像普通的锁那样,如果获取不到锁就进入阻塞。原创 2022-01-09 12:29:02 · 345 阅读 · 0 评论 -
java并发编程(三十六)——初识读写锁
前言在没有读写锁之前,我们假设使用普通的 ReentrantLock,那么虽然我们保证了线程安全,但是也浪费了一定的资源,因为如果多个读操作同时进行,其实并没有线程安全问题,我们可以允许让多个读操作并行,以便提高程序效率。但是写操作不是线程安全的,如果多个线程同时写,或者在写的同时进行读操作,便会造成线程安全问题。我们的读写锁就解决了这样的问题,它设定了一套规则,既可以保证多个线程同时读的效率,同时又可以保证有写入操作时的线程安全。我们来学习下读写锁的规则及用法。读写锁简介读写锁的整体思路是它原创 2022-01-09 12:23:45 · 437 阅读 · 0 评论 -
java并发编程(三十五)——公平与非公平锁实战
前言在 java并发编程(十六)——锁的七大分类及特点 一文中我们对锁有各个维度的分类,其中有一个维度是公平/非公平,本文我们来探讨下公平与非公平锁。公平|非公平首先,我们来看下什么是公平锁和非公平锁,公平锁指的是按照线程请求的顺序,来分配锁;而非公平锁指的是不完全按照请求的顺序,在一定情况下,可以允许插队。但需要注意这里的非公平并不是指完全的随机,不是说线程可以任意插队,而是仅仅“在合适的时机”插队。那么什么时候是合适的时机呢?假设当前线程在请求获取锁的时候,恰巧前一个持有锁的线程释放了这把锁,那原创 2022-01-09 12:21:27 · 404 阅读 · 0 评论 -
java并发编程(三十四)——并发工具之CopyOnWriteArrayList详解
前言在 CopyOnWriteArrayList 出现之前,我们已经有了 ArrayList 和 LinkedList 作为 List 的数组和链表的实现,而且也有了线程安全的 Vector 和 Collections.synchronizedList() 可以使用。所以首先就让我们来看下线程安全的 Vector 的 add方法的代码:/** * Appends the specified element to the end of this Vector. * * @pa原创 2022-01-09 12:19:13 · 285 阅读 · 0 评论 -
java并发编程(三十三)——HashMap为什么是线程不安全的?
问题我们来探讨一个问题:HashMap 为什么是线程不安全的?我们都听说过hashmap不是线程安全的类,那么它的线程不安全到底是如何体现的呢?我们来从源码等几个角度来探究一下。源码角度put()方法内部调用了putVal()方法,putVal()的源码如下: final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V&原创 2022-01-09 12:18:40 · 801 阅读 · 0 评论 -
java并发编程(三十二)——初识原子类
简介在编程领域里,原子性意味着“一组操作要么全都操作成功,要么全都失败,不能只操作成功其中的一部分”。而 java.util.concurrent.atomic 下的类,就是具有原子性的类,可以原子性地执行添加、递增、递减等操作。比如之前多线程下的线程不安全的 i++ 问题,到了原子类这里,就可以用功能相同且线程安全的 getAndIncrement 方法来优雅地解决。原子类的作用和锁有类似之处,是为了保证并发情况下线程安全。不过原子类相比于锁,有一定的优势:粒度更细:原子变量可以把竞争范围缩小到变原创 2022-01-06 22:59:27 · 153 阅读 · 0 评论 -
java并发编程(三十一)——初识CyclicBarrier
CyclicBarrier简介CyclicBarrier 和 CountDownLatch 确实有一定的相似性,它们都能阻塞一个或者一组线程,直到某种预定的条件达到之后,这些之前在等待的线程才会统一出发,继续向下执行。正因为它们有这个相似点,有些人可能会认为它们的作用是完全一样的,其实并不是。CyclicBarrier 可以构造出一个集结点,当某一个线程执行 await() 的时候,它就会到这个集结点开始等待,等待这个栅栏被撤销。直到预定数量的线程都到了这个集结点之后,这个栅栏就会被撤销,之前等待的线程原创 2022-01-06 22:58:44 · 135 阅读 · 0 评论 -
java并发编程(三十)——CountDownLatch的使用场景
CountDownLatch简介CountDownLatch,是 JDK 提供的并发流程控制的工具类,它是在 java.util.concurrent 包下,在 JDK1.5 以后加入的。下面我们来举个例子来说明它主要在什么场景下使用。场景比如我们去游乐园坐激流勇进,有的时候游乐园里人不是那么多,这时,管理员会让你稍等一下,等人坐满了再开船,这样的话可以在一定程度上节约游乐园的成本。座位有多少,就需要等多少人,这就是 CountDownLatch 的核心思想,等到一个设定的数值达到之后,才能出发。把原创 2022-01-04 13:53:20 · 536 阅读 · 0 评论 -
java并发编程(二十九)——浅谈信号量
信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。为了完成这个过程,需要创建一个信号量VI,然后将Acquire Semaphore VI以及Release Semaphore VI分别放置在每个关键代码段的首末端。确认这些信号量VI引用的是初始创建的信号量。原创 2022-01-03 12:20:08 · 4272 阅读 · 1 评论 -
java并发编程(二十八)——剖析线程池“复用线程”的原理
线程池可以把线程和任务进行解耦,线程归线程,任务归任务,摆脱了之前通过 Thread 创建线程时的一个线程必须对应一个任务的限制。在线程池中,同一个线程可以从 BlockingQueue 中不断提取新任务来执行,其核心原理在于线程池对 Thread 进行了封装,并不是每次执行任务都会调用 Thread.start() 来创建新线程,而是让每个线程去执行一个“循环任务”。原创 2022-01-03 12:18:34 · 257 阅读 · 0 评论 -
java并发编程(二十七)——自定义线程池
前言在Java并发编程(十)——常见几种线程池 中我们学习了常见的几种线程池,创建线程池的方法有两种,一种是手动创建,一种是自动创建。所谓自动创建线程池就是直接调用 Executors 的各种方法来生成前面学过的常见的线程池,例如 Executors.newCachedThreadPool()。本文我们来分析自动创建线程池所可能带来的问题,以及我们自定义线程池时需要考虑的重点参数。FixedThreadPool第一种线程池 FixedThreadPool, 它是线程数量固定的线程池,如源码所示,ne原创 2022-01-03 12:16:25 · 1344 阅读 · 0 评论 -
java并发编程(二十六)——单例模式的双重检查锁模式为什么必须加 volatile?
我们为什么需要单例呢?其中**一个理由,那就是为了节省内存、节省计算。**因为在很多情况下,我们只需要一个实例就够了,如果出现更多的实例,反而纯属浪费。原创 2022-01-03 12:13:55 · 767 阅读 · 0 评论 -
java并发编程(二十五)——volatile初识
volatile 是什么首先我们就来介绍一下 volatile,它是 Java 中的一个关键字,是一种同步机制。当某个变量是共享变量,且这个变量是被 volatile 修饰的,那么在修改了这个变量的值之后,再读取该变量的值时,可以保证获取到的是修改后的最新的值,而不是过期的值。相比于 synchronized 或者 Lock,volatile 是更轻量的,因为使用 volatile 不会发生上下文切换等开销很大的情况,不会让线程阻塞。但正是由于它的开销相对比较小,所以它的效果,也就是能力,相对也小一些。原创 2022-01-02 17:24:42 · 166 阅读 · 0 评论 -
java并发编程(二十四)——什么是-happens-before-规则?
前言在前面我们研究了Java内存模型中重排序、原子性、内存可见性三方面最主要的内容,不了解的读者请移步java并发编程(二十三)——深入探究Java内存模型 。本文我们深入剖析下与内存可见性相关的Happens-before 关系,以对内存可见性有更深入的了解。什么是 happens-before 关系Happens-before 关系是用来描述和可见性相关问题的:如果第一个操作 happens-before 第二个操作(也可以描述为,第一个操作和第二个操作之间满足 happens-before 关系原创 2022-01-02 17:23:22 · 127 阅读 · 0 评论 -
java并发编程(二十三)——深入探究Java内存模型
内存系统内不存在真正的重排序,但是内存会带来看上去和重排序一样的效果,所以这里的“重排序”打了双引号。由于内存有缓存的存在,在 JMM 里表现为主存和本地内存,而主存和本地内存的内容可能不一致,所以这也会导致程序表现出乱序的行为。原创 2021-12-30 22:10:06 · 173 阅读 · 0 评论 -
java并发编程(二十二)——初识Java内存模型
前面我们学习了一些并发的基础知识,常见的并发工具的使用,但是我们仅仅是停留在使用的阶段,要想了解Java并发的底层原理,要知其所以然,还得更进一步学习一些Java内存模型的知识。本文我们来深入研究下与Java并发息息相关的Java内存模型的相关知识。原创 2021-12-30 21:54:21 · 173 阅读 · 0 评论