
Java基础
文章平均质量分 71
Java基础
程序员资料站
目前在一线互联网大厂,乐于给大家传播分享各种资料,交个朋友。
展开
-
都啥年头了,还问这种面试题
两道经典面试题灵魂拷问,我hold不住了原创 2022-01-22 19:46:09 · 524 阅读 · 0 评论 -
面试官:来说一说缓存雪崩、缓存穿透、缓存击穿的区别?我整个人都懵了
前言本文我们整理总结下Redis使用过程中一些常见的问题,并研究如何解决。缓存穿透一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。简介缓存穿透是指在高并发下查询key不存在的数据,会穿过缓存查询数据库。导致数据库压力过大而宕机 。解决方案解决方案:对查询结果为空的情况也进行缓存,缓存时间(ttl)设置短一点,或者该key对应的数据insert了之后清理缓存。存在的问题:缓存太多空值占用了更多的空间使用布隆过滤器。在缓存之前原创 2022-01-20 19:37:46 · 2008 阅读 · 2 评论 -
缓存“延时双删”真的有必要吗?我觉得没有
第一次清空缓存后,更新数据库前的这段时间内,其他事务查询了数据库的数据,第二次清空缓存后,刚才查询数据库 的那个线程又更新了缓存,此时又会将旧数据更新到缓存原创 2022-01-19 13:37:42 · 6281 阅读 · 1 评论 -
大厂面试十大真题(附有详细解答)
大厂面试十大真题,并附有详细解答,供大家学习,文末有额外大礼包资料及内推哦。原创 2022-01-18 13:59:53 · 1003 阅读 · 0 评论 -
学会了伪共享问题解决方案,又能涨薪了
前言学习的过程中遇到了一个名词——“伪共享”,出于对知识的兴趣,上网查阅了一些博文,研究了“伪共享”的问题,写此文章总结记录。要很好的理解伪共享问题,我们要先从CPU的缓存开始说起。CPU缓存架构CPU 是计算机的心脏,所有运算和程序最终都要由它来执行。主内存(RAM)是数据存放的地方,CPU 和主内存之间有好几级缓存,因为即使直接访问主内存也是非常慢的。如果对一块数据做相同的运算多次,那么在执行运算的时候把它加载到离 CPU 很近的地方就有意义了,比如一个循环计数,你不想每次循环都跑到主内存原创 2022-01-17 13:50:44 · 318 阅读 · 1 评论 -
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 · 300 阅读 · 0 评论 -
JVM如何判断一个对象是否存活?
前言在 深入浅出Java虚拟机(三)——初识JVM的垃圾回收机制 中我们介绍了如何判断对象已死的两种算法,分别是引用计数法和可达性分析法。本文我们再来详细说明一下JVM中判断对象是否、存活的相关细节。finalize()方法的执行条件即使在可达性分析算法中判定为不可达的对象, 也不是“非死不可”的, 这时候它们暂时还处于“缓刑”阶段, 要真正宣告一个对象死亡, 至少要经历两次标记过程:第一次标记:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链, 那它将会被第一次标记, 随后进原创 2022-01-15 10:30:00 · 656 阅读 · 0 评论 -
手把手教你如何自定义一个类加载器
前言前面 认识类加载器及双亲委派模型/ 中我们认识了类加载器,本文我们来自定义一个类加载器。为什么需要自定义类加载器?既然JDK已经有类加载器了,为什么还需要自定义类加载器呢?大概有以下几个原因:隔离加载类模块隔离,将类加载到不同的应用程序中。比如Tomcat这类web应用服务器,内部定义了好几种类加载器,用于隔离web应用服务器上不同的应用程序。扩展加载源 还可以从数据库、网络或其他终端上加载类防止源码泄露 Java代码容易被编译和篡改,可以进原创 2022-01-14 14:12:27 · 3411 阅读 · 1 评论 -
认识类加载器及双亲委派模型
类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。>注意:JVM主要在程序第一次主动使用类的时候,才会去加载该类,也就是说,JVM并不是在一开始就把一个>程序就所有的类都加载到内存中,而是到不得不用的时候才把它加载进来,而且只加载一次。原创 2022-01-14 14:09:41 · 319 阅读 · 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 · 731 阅读 · 0 评论 -
JVM中类加载的过程详解
类从被加载到虚拟机内存中开始,到卸载出内存,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initiallization)、使用(Using)和卸载(Unloading)这7个阶段。其中验证、准备、解析3个部分统称为连接(Linking)原创 2022-01-13 19:10:32 · 628 阅读 · 0 评论 -
Java虚拟机栈的出栈入栈流程及栈内存大小设置
Java虚拟机栈(Java Virtual Machine Stacks)是线程私有的,即生命周期和线程相同。Java虚拟机栈和线程同时创建,用于存储栈帧。每个方法在执行时都会创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直到执行完成的过程就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。原创 2022-01-13 19:07:52 · 2646 阅读 · 2 评论 -
Java虚拟机(三)——初识JVM的垃圾回收机制
前言对于程序计数器、虚拟机栈、本地方法栈这三个部分而言,其生命周期与相关线程有关,随线程而生,随线程而灭。并且这三个区域的内存分配与回收具有确定性,因为当方法结束或者线程结束时,内存就自然跟着线程回收了。因此本篇文章所讲的有关内存分配和回收关注的是Java堆与方法区这两个区域。如何判断对象已死?1. 引用计数法简介给对象增加一个引用计数器,每当有一个地方引用它时,计数器就+1;当引用失效时,计数器就-1;任何时刻计数器为0的对象就是不能再被使用的,即对象已“死”。引用计数法实现简单,判定效率也比原创 2022-01-12 19:39:21 · 340 阅读 · 0 评论 -
深入浅出Java虚拟机(二)——Java内存模型
前言我们从一个问题入手来进行对JVM的深入理解。JVM的内存区域是怎么高效划分的?为什么要问到 JVM 的内存区域划分呢?因为 Java 引以为豪的就是它的自动内存管理机制。相比于 C++的手动内存管理、复杂难以理解的指针等,Java 程序写起来就方便的多。然而这种呼之即来挥之即去的内存申请和释放方式,自然也有它的代价。为了管理这些快速的内存申请释放操作,就必须引入一个池子来延迟这些内存区域的回收操作。我们常说的内存回收,就是针对这个池子的操作。我们把上面说的这个池子,叫作堆,可以暂时把它看成一个原创 2022-01-12 19:37:55 · 310 阅读 · 0 评论 -
深入浅出Java虚拟机(一)——初识JVM
什么是JVMJVM 全称 Java Virtual Machine,也就是我们耳熟能详的 Java 虚拟机。它能识别 .class后缀的文件,并且能够解析它的指令,最终调用操作系统上的函数,完成我们想要的操作。一般情况下,使用 C++ 开发的程序,编译成二进制文件后,就可以直接执行了,操作系统能够识别它;但是 Java 程序不一样,使用 javac 编译成 .class 文件之后,还需要使用 Java 命令去主动执行它,操作系统并不认识这些 .class 文件。Java 程序和我们通常使用的 C++原创 2022-01-12 19:34:21 · 342 阅读 · 0 评论 -
java并发编程(三十八)——“死锁“的发生及修复策略
前言锁是我们之前常使用的并发工具,但有时候也会有一些问题,比如死锁。本文我们来了解下死锁相关的知识。简介死锁一定发生在并发场景中。我们为了保证线程安全,有时会给程序使用各种能保证并发安全的工具,尤其是锁,但是如果在使用过程中处理不得当,就有可能会导致发生死锁的情况。死锁是一种状态,当两个(或多个)线程(或进程)相互持有对方所需要的资源,却又都不主动释放自己手中所持有的资源,导致大家都获取不到自己想要的资源,所有相关的线程(或进程)都无法继续往下执行,在未改变这种状态之前都不能向前推进,我们就把这种状原创 2022-01-12 19:31:15 · 309 阅读 · 0 评论 -
java并发编程(三十七)——什么是自旋锁?
“自旋”可以理解为“自我旋转”,这里的“旋转”指“循环”,比如 while 循环或者 for 循环。“自旋”就是自己在这里不停地循环,直到目标达成。而不像普通的锁那样,如果获取不到锁就进入阻塞。原创 2022-01-09 12:29:02 · 365 阅读 · 0 评论 -
java并发编程(三十六)——初识读写锁
前言在没有读写锁之前,我们假设使用普通的 ReentrantLock,那么虽然我们保证了线程安全,但是也浪费了一定的资源,因为如果多个读操作同时进行,其实并没有线程安全问题,我们可以允许让多个读操作并行,以便提高程序效率。但是写操作不是线程安全的,如果多个线程同时写,或者在写的同时进行读操作,便会造成线程安全问题。我们的读写锁就解决了这样的问题,它设定了一套规则,既可以保证多个线程同时读的效率,同时又可以保证有写入操作时的线程安全。我们来学习下读写锁的规则及用法。读写锁简介读写锁的整体思路是它原创 2022-01-09 12:23:45 · 456 阅读 · 0 评论 -
java并发编程(三十五)——公平与非公平锁实战
前言在 java并发编程(十六)——锁的七大分类及特点 一文中我们对锁有各个维度的分类,其中有一个维度是公平/非公平,本文我们来探讨下公平与非公平锁。公平|非公平首先,我们来看下什么是公平锁和非公平锁,公平锁指的是按照线程请求的顺序,来分配锁;而非公平锁指的是不完全按照请求的顺序,在一定情况下,可以允许插队。但需要注意这里的非公平并不是指完全的随机,不是说线程可以任意插队,而是仅仅“在合适的时机”插队。那么什么时候是合适的时机呢?假设当前线程在请求获取锁的时候,恰巧前一个持有锁的线程释放了这把锁,那原创 2022-01-09 12:21:27 · 450 阅读 · 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 · 310 阅读 · 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 · 830 阅读 · 0 评论 -
java并发编程(三十二)——初识原子类
简介在编程领域里,原子性意味着“一组操作要么全都操作成功,要么全都失败,不能只操作成功其中的一部分”。而 java.util.concurrent.atomic 下的类,就是具有原子性的类,可以原子性地执行添加、递增、递减等操作。比如之前多线程下的线程不安全的 i++ 问题,到了原子类这里,就可以用功能相同且线程安全的 getAndIncrement 方法来优雅地解决。原子类的作用和锁有类似之处,是为了保证并发情况下线程安全。不过原子类相比于锁,有一定的优势:粒度更细:原子变量可以把竞争范围缩小到变原创 2022-01-06 22:59:27 · 177 阅读 · 0 评论 -
java并发编程(三十一)——初识CyclicBarrier
CyclicBarrier简介CyclicBarrier 和 CountDownLatch 确实有一定的相似性,它们都能阻塞一个或者一组线程,直到某种预定的条件达到之后,这些之前在等待的线程才会统一出发,继续向下执行。正因为它们有这个相似点,有些人可能会认为它们的作用是完全一样的,其实并不是。CyclicBarrier 可以构造出一个集结点,当某一个线程执行 await() 的时候,它就会到这个集结点开始等待,等待这个栅栏被撤销。直到预定数量的线程都到了这个集结点之后,这个栅栏就会被撤销,之前等待的线程原创 2022-01-06 22:58:44 · 147 阅读 · 0 评论 -
java并发编程(三十)——CountDownLatch的使用场景
CountDownLatch简介CountDownLatch,是 JDK 提供的并发流程控制的工具类,它是在 java.util.concurrent 包下,在 JDK1.5 以后加入的。下面我们来举个例子来说明它主要在什么场景下使用。场景比如我们去游乐园坐激流勇进,有的时候游乐园里人不是那么多,这时,管理员会让你稍等一下,等人坐满了再开船,这样的话可以在一定程度上节约游乐园的成本。座位有多少,就需要等多少人,这就是 CountDownLatch 的核心思想,等到一个设定的数值达到之后,才能出发。把原创 2022-01-04 13:53:20 · 572 阅读 · 0 评论 -
java并发编程(二十九)——浅谈信号量
信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。为了完成这个过程,需要创建一个信号量VI,然后将Acquire Semaphore VI以及Release Semaphore VI分别放置在每个关键代码段的首末端。确认这些信号量VI引用的是初始创建的信号量。原创 2022-01-03 12:20:08 · 4340 阅读 · 1 评论 -
java并发编程(二十八)——剖析线程池“复用线程”的原理
线程池可以把线程和任务进行解耦,线程归线程,任务归任务,摆脱了之前通过 Thread 创建线程时的一个线程必须对应一个任务的限制。在线程池中,同一个线程可以从 BlockingQueue 中不断提取新任务来执行,其核心原理在于线程池对 Thread 进行了封装,并不是每次执行任务都会调用 Thread.start() 来创建新线程,而是让每个线程去执行一个“循环任务”。原创 2022-01-03 12:18:34 · 293 阅读 · 0 评论 -
java并发编程(二十七)——自定义线程池
前言在Java并发编程(十)——常见几种线程池 中我们学习了常见的几种线程池,创建线程池的方法有两种,一种是手动创建,一种是自动创建。所谓自动创建线程池就是直接调用 Executors 的各种方法来生成前面学过的常见的线程池,例如 Executors.newCachedThreadPool()。本文我们来分析自动创建线程池所可能带来的问题,以及我们自定义线程池时需要考虑的重点参数。FixedThreadPool第一种线程池 FixedThreadPool, 它是线程数量固定的线程池,如源码所示,ne原创 2022-01-03 12:16:25 · 1393 阅读 · 0 评论 -
java并发编程(二十六)——单例模式的双重检查锁模式为什么必须加 volatile?
我们为什么需要单例呢?其中**一个理由,那就是为了节省内存、节省计算。**因为在很多情况下,我们只需要一个实例就够了,如果出现更多的实例,反而纯属浪费。原创 2022-01-03 12:13:55 · 828 阅读 · 0 评论 -
java并发编程(二十五)——volatile初识
volatile 是什么首先我们就来介绍一下 volatile,它是 Java 中的一个关键字,是一种同步机制。当某个变量是共享变量,且这个变量是被 volatile 修饰的,那么在修改了这个变量的值之后,再读取该变量的值时,可以保证获取到的是修改后的最新的值,而不是过期的值。相比于 synchronized 或者 Lock,volatile 是更轻量的,因为使用 volatile 不会发生上下文切换等开销很大的情况,不会让线程阻塞。但正是由于它的开销相对比较小,所以它的效果,也就是能力,相对也小一些。原创 2022-01-02 17:24:42 · 185 阅读 · 0 评论 -
java并发编程(二十四)——什么是-happens-before-规则?
前言在前面我们研究了Java内存模型中重排序、原子性、内存可见性三方面最主要的内容,不了解的读者请移步java并发编程(二十三)——深入探究Java内存模型 。本文我们深入剖析下与内存可见性相关的Happens-before 关系,以对内存可见性有更深入的了解。什么是 happens-before 关系Happens-before 关系是用来描述和可见性相关问题的:如果第一个操作 happens-before 第二个操作(也可以描述为,第一个操作和第二个操作之间满足 happens-before 关系原创 2022-01-02 17:23:22 · 144 阅读 · 0 评论 -
java并发编程(二十三)——深入探究Java内存模型
内存系统内不存在真正的重排序,但是内存会带来看上去和重排序一样的效果,所以这里的“重排序”打了双引号。由于内存有缓存的存在,在 JMM 里表现为主存和本地内存,而主存和本地内存的内容可能不一致,所以这也会导致程序表现出乱序的行为。原创 2021-12-30 22:10:06 · 199 阅读 · 0 评论 -
java并发编程(二十二)——初识Java内存模型
前面我们学习了一些并发的基础知识,常见的并发工具的使用,但是我们仅仅是停留在使用的阶段,要想了解Java并发的底层原理,要知其所以然,还得更进一步学习一些Java内存模型的知识。本文我们来深入研究下与Java并发息息相关的Java内存模型的相关知识。原创 2021-12-30 21:54:21 · 191 阅读 · 0 评论 -
java并发编程(二十一)——CAS算法思想的应用场景
CAS的英文全称是 Compare-And-Swap,中文叫做“比较并交换”,它是一种思想、一种算法。在多线程的情况下,各个代码的执行顺序是不能确定的,所以为了保证并发安全,我们可以使用互斥锁。而 CAS 的特点是避免使用互斥锁,当多个线程同时使用 CAS 更新同一个变量时,只有其中一个线程能够操作成功,而其他线程都会更新失败。不过和同步互斥锁不同的是,更新失败的线程并不会被阻塞,而是被告知这次由于竞争而导致的操作失败,但还可以再次尝试。CAS 被广泛应用在并发编程领域中,以实现那些不会被打断的数据原创 2021-12-30 16:19:28 · 1604 阅读 · 0 评论 -
java并发编程(二十)——Lock初识
Lock 接口是 Java 5 引入的,最常见的实现类是 ReentrantLock,可以起到“锁”的作用。Lock 和 synchronized 是两种最常见的锁,锁是一种工具,用于控制对共享资源的访问,而 Lock 和 synchronized 都可以达到线程安全的目的,但是在使用上和功能上又有较大的不同。所以 Lock 并不是用来代替 synchronized 的,而是当使用 synchronized 不合适或不足以满足要求的时候,Lock 可以用来提供更高级功能的。原创 2021-12-30 16:15:30 · 307 阅读 · 0 评论 -
java并发编程(十九)——Callable及Future实战
我们来对callable及future实现线程的常见用法进行探究学习原创 2021-12-30 16:14:10 · 615 阅读 · 0 评论 -
java并发编程(十八)——深入剖析synchronized底层实现(建议反复阅读系列)
被 synchronized 修饰的方法会有一个 ACC_SYNCHRONIZED 标志。当某个线程要访问某个方法的时候,会首先检查方法是否有 ACC_SYNCHRONIZED 标志,如果有则需要先获得 monitor 锁,然后才能开始执行方法,方法执行之后再释放 monitor 锁。其他方面, synchronized 方法和刚才的 synchronized 代码块是很类似的,例如这时如果其他线程来请求执行方法,也会因为无法获得 monitor 锁而被阻塞。原创 2021-12-30 09:12:51 · 362 阅读 · 0 评论 -
java并发编程(十七)——深入剖析乐观锁-悲观锁(建议主动收藏系列)
乐观锁比较乐观,认为自己在操作资源的时候不会有其他线程来干扰,所以并不会锁住被操作对象,不会不让别的线程来接触它,同时,为了确保数据正确性,在更新之前,会去对比在我修改数据期间,数据有没有被其他线程修改过:如果没被修改过,就说明真的只有我自己在操作,那我就可以正常的修改数据;如果发现数据和我一开始拿到的不一样了,说明其他线程在这段时间内修改过数据,那说明我迟了一步,所以我会放弃这次修改,并选择报错、重试等策略。原创 2021-12-30 09:10:10 · 324 阅读 · 0 评论 -
java并发编程(十六)——锁的七大分类及特点
前言在处理并发相关的问题时,我们首先想到的一个解决方案就是给共享的资源加锁,实现同一时刻对同一个资源的互斥访问,本文我们来学习下锁的相关知识。锁的分类比如评价一个城市,标准有人口多少、经济发达与否、城市面积大小等,这些都是评价事物的标准,而一个城市可能同时占据多个标准,以北京而言,人口多,经济发达,同时城市面积还很大。同理,对于 Java 中的锁而言,一把锁也有可能同时占有多个标准,符合多种分类,比如 ReentrantLock 既是可中断锁,又是可重入锁。根据分类的标准,我们把锁分为7大类,分别原创 2021-12-30 09:07:27 · 351 阅读 · 1 评论 -
java并发编程(十五)——常见的几种阻塞队列
前言我们来看一下Java中常见的几种的阻塞队列的相关知识。主要并发队列Java中队列的接口是Queue,其实现类如下图所示:分为阻塞队列和非阻塞队列两种。何为阻塞队列阻塞队列,也就是BlockingQueue,是一个接口,它的源码定义如下:public interface BlockingQueue<E> extends Queue<E> { void put(E e) throws InterruptedException; boolean offe原创 2021-12-29 13:01:01 · 1082 阅读 · 0 评论 -
java并发编程(十四)——深入剖析ThreadLocal
本文通过四个问题来深入剖析ThreadLocal的源码,从而使读者对ThreadLocal有更深层次的理解。原创 2021-12-29 12:58:22 · 350 阅读 · 0 评论