Java
文章平均质量分 59
海平面远方开始阴霾
这个作者很懒,什么都没留下…
展开
-
TCP/IP四次挥手三次握手小故事
一点感悟:四次挥手最后是服务器发了fin但是不确定客户端是否收到了,所以需要等客户端回复一个收到了。四次挥手:(5个端点四条箭头)C: 喂我要断线了。S: 要得, 等我一哈。S: 我弄完了,断嘛。C: ok,我断了。S: ok,我也断了。三次握手:(4个端点,3个箭头)客户端需要知道发出去的连接请求是否被服务端收到,当它收到服务端的回复,得知服务端收到时就立刻连接上自己这一头并回复,而后服务端也知道客户端已接收到自己的回复,因此服务端也连接上自己这一头。从而双工的连接建立了。C: 请求连接原创 2021-09-23 23:16:01 · 206 阅读 · 0 评论 -
缓存常用的3种读写策略
Cache Aside Pattern(旁路缓存模式)Cache Aside Pattern 是我们平时使用比较多的一个缓存读写模式,比较适合读请求比较多的场景。Cache Aside Pattern 中服务端需要同时维系 DB 和 cache,并且是以 DB 的结果为准。写 :先更新 DB然后直接删除 cache 。、读 :从 cache 中读取数据,读取到就直接返回cache中读取不到的话,就从 DB 中读取数据返回再把数据放到 cache 中。“那么原创 2021-07-14 15:00:02 · 284 阅读 · 0 评论 -
分布式锁 笔记
Martin Kleppmann 的文章 How to do distributed locking 部分内容的翻译和总结开篇作者认为现在 Redis 逐渐被使用到数据管理领域,这个领域需要更强的数据一致性和耐久性,这使得他感到担心,因为这不是 Redis 最初设计的初衷(事实上这也是很多业界程序员的误区,越来越把 Redis 当成数据库在使用),其中基于 Redis 的分布式锁就是令人担心的其一。Martin 指出首先你要明确你为什么使用分布式锁,为了性能还是正确性?为了帮你区分这二者,在这把锁 fa原创 2021-07-14 13:29:55 · 191 阅读 · 0 评论 -
redis集群
原理主从复制复制模式全量复制:Master 全部同步到 Slave部分复制:Slave 数据丢失进行备份问题点:同步故障复制数据延迟(不一致)读取过期数据(Slave 不能删除数据)(为什么Slave 不能删除数据就导致了可能读取过期数据呢?)从节点故障主节点故障配置不一致maxmemory 不一致:丢失数据优化参数不一致:内存不一致.避免全量复制选择小主节点(分片)、低峰期间操作.如果节点运行 id 不匹配(如主节点重启、运行 id 发生变化),此时要执行全原创 2021-07-14 10:37:47 · 92 阅读 · 0 评论 -
Redis 单线程模型详解
Redis 基于 Reactor 模式来设计开发了自己的一套高效的事件处理模型 (Netty 的线程模型也基于 Reactor 模式,Reactor 模式不愧是高性能 IO 的基石),这套事件处理模型对应的是 Redis 中的文件事件处理器(file event handler)。由于文件事件处理器(file event handler)是单线程方式运行的,所以我们一般都说 Redis 是单线程模型。Redis 通过IO 多路复用程序 来监听来自客户端的大量连接(或者说是监听多个 socket),它会将感原创 2021-07-13 23:27:44 · 977 阅读 · 0 评论 -
Redis数据类型
Redis 就是一个使用 C 语言开发的数据库, Redis 的数据是存在内存中的,所以读写速度非常快。Redis 除了做缓存之外,也经常用来做分布式锁,甚至是消息队列。Redis 提供了多种数据类型来支持不同的业务场景。Redis 还支持事务 、持久化、Lua 脚本、多种集群方案。缓存数据处理流程:如果用户请求的数据在缓存中就直接返回。缓存中不存在的话就看数据库中是否存在。数据库中存在的话就更新缓存中的数据。数据库中不存在的话就返回空数据。注:QPS(Query Per Second)原创 2021-07-13 16:13:00 · 92 阅读 · 0 评论 -
Redis 主从架构 笔记与疑问
对于缓存来说,一般都是用来支撑读高并发的。因此架构做成主从(master-slave)架构,一主多从,主负责写,并且将数据复制到其它的 slave 节点,从节点负责读。所有的读请求全部走从节点。这样也可以很轻松实现水平扩容,支撑读高并发。redis replication -> 主从架构 -> 读写分离 -> 水平扩容支撑读高并发redis replication 的核心机制redis 采用异步方式复制数据到 slave 节点,不过 redis2.8 开始,slave node原创 2021-07-13 15:23:03 · 150 阅读 · 0 评论 -
Java浅复制和深复制
浅复制就是复制对象中的基本数据类型,但对于对象中的引用类型只复制其引用;深复制则是不止复制对象中的基本数据类型,而且复制对象中的引用指向的所有对象。Java中要实现深复制,可以先使对象实现Serializable接口,然后把对象写到一个流里,再从流里读出来重建对象。(常见的深复制实现)。需要注意的是,代码中不仅Person类要实现Serializable接口,它内部的School类也要实现Serializable接口。public class deepCopy { public static原创 2021-07-12 20:01:33 · 271 阅读 · 0 评论 -
通过反射机制修改数组的大小
这个修改数组大小实际上只是通过反射新建一个数组,再把原数组的值copy过去嘛。public class TestReflect { public static void main(String[] args) throws Exception { int[] temp = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int[] newTemp = (int[]) arrayInc(temp, 15); print(newTemp);原创 2021-07-12 17:17:14 · 149 阅读 · 0 评论 -
在泛型为Integer的ArrayList中存放一个String类型的对象
在getMethod(“add”, Object.class)时Object.class通过相当于通过重载得到了ArrayList类的add(Object)方法,于是就可以对这个方法传入Object对象,因此可以用这个方法在泛型为Integer的ArrayList中存放一个String类型的对象。import java.lang.reflect.Method;import java.util.ArrayList;public class TestReflect { public static原创 2021-07-12 17:09:19 · 602 阅读 · 0 评论 -
Java反射与动态代理
动态代理使用反射可以在运行时创建接口的动态实现,java.lang.reflect.Proxy类提供了创建动态实现的功能。我们把运行时创建接口的动态实现称为动态代理。应用有例如数据库连接和事务管理、用于单元测试的动态模拟对象以及其他类似aop的方法拦截等。创建动态代理调用java.lang.reflect.Proxy类的newProxyInstance()方法就可以创见动态代理,newProxyInstance()方法有三个参数: 1、用于“加载”动态代理类的类加载器。2、要实现的接口数组。 3、将代原创 2021-07-12 16:40:46 · 89 阅读 · 0 评论 -
Java反射 笔记
Java的反射机制是指在运行状态中,对于任意一个类都能够知道这个类的所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法。Java对象中许多对象运行时都会出现两种类型:编译时类型和运行时类型。编译时类型由声明对象时使用的类型决定,运行时的类型由实际赋值给对象的类型决定。如:Person p=new Student;其中编译时类型为Person,运行时类型为Student。但是编译时类型无法获取具体方法。程序在运行时还可能接收到外部传入的对象,该对象的编译时类型为Object,但是程序原创 2021-07-11 20:07:28 · 84 阅读 · 1 评论 -
抽象类与接口的区别
相同点:抽象类和接口都不能直接实例化,接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法后才能实例化。区别:接口的普通方法只能有定义,不能有实现,jdk1.8后接口中的default方法才可以实现。而抽象类的方法可以在抽象类中实现。一个类可以实现多个接口,但只能继承一个抽象类。接口的成员变量默认为public static final,必须赋初值(这是由final决定的),不能被修改(也是由final决定的);其所有成员方法都是public abstract的(因此必须实现)。抽象类中的成原创 2021-07-10 11:23:57 · 122 阅读 · 0 评论 -
线程池工作原理
Java线程池工作过程线程池创建时里面没有线程,任务队列时作为参数传进来的。不过即使队列里有任务,线程池也不会马上执行它。当调用execute方法添加一个任务时,线程池会判断,如果运行的线程数量小于corePoolSize(核心线程数),就创建核心线程执行该任务;如果正在运行的线程数大于等于核心线程数,就把任务放入任务队列;当队列满了且运行的线程数没达到maximumPoolSize(最大线程数),就创建非核心线程立即执行任务;如果任务队列满了且线程数已经达到最大线程数,就拒绝(抛出RejectExe原创 2021-07-10 10:27:03 · 2041 阅读 · 1 评论 -
java线程的五大状态,阻塞状态 笔记
状态简介一个线程生命周期里有五大状态:新生、就绪、运行、死亡、运行后可能遇到的阻塞状态。新生态:Thread t=new Thread();一个线程开始之后有私有的工作内存,工作内存和主内存交互,从主内存拷贝数据到工作内存。当线程创建,开辟工作内存,线程就进入了新生态;就绪态:t.start(); start方法被调用,线程进入就绪态,这表示线程有了运行的条件,但还没开始运行。注意线程就绪还要等待CPU调度运行,一般是进入就绪队列。进入就绪状态还有3情况:从阻塞状态解除;运行的时候调用yie原创 2021-07-09 21:10:05 · 533 阅读 · 0 评论 -
AbstractQueuedSynchronizer(AQS)笔记
框架AQS维护了一个volatile int state(代表共享资源)和一个FIFO线程等待队列(多线程争用资源被阻塞时会进入此队列)。(这个等待队列是LRU算法实现的吧)这个state的访问方式有3种:getState()setState()compareAndSetState()AQS定义两种资源共享方式:Exclusive(独占,只有一个线程能执行,如ReentrantLock)和Share(共享,多个线程可同时执行,如Semaphore/CountDownLatch)。自定义同步器在原创 2021-07-09 11:48:03 · 94 阅读 · 1 评论 -
线程死锁原理笔记
死锁就是多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源(是指被其他线程占用的资源吧,互相都在等对方释放才进行下一步,这是三个和尚没水喝)被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。如下图所示,线程 A 持有资源 2,线程 B 持有资源 1,他们同时都想申请对方的资源,所以这两个线程就会互相等待而进入死锁状态。代码示例:线程1运行到要获取resource2,同时线程2也运行到获取resource1锁的位置,就发生死锁。(flag)因为线程1已经占用resource1,线程2无法获原创 2021-07-09 10:44:04 · 177 阅读 · 2 评论 -
ReentrantLock与synchronized
ReentrantLock通过方法lock(),unlock()来加锁解锁,加锁后需要手动解锁,一般在finally里解锁,而synchronized会被JVM自动解锁。ReentrantLock比synchronized多了的功能又可中断、公平锁、多个锁。公平锁是通过一个先进先出的队列实现的,但比非公平锁的效率要低很多。...原创 2021-07-08 17:58:31 · 70 阅读 · 0 评论 -
synchronized 底层实现原理笔记与质问
调用wait方法被阻塞的线程放在Wait Set里(wait set就是阻塞队列?);所有请求锁的线程首先被放在Contention List竞争队列里(所以尚未进入contention list的线程不会和OnDeck竞争锁?);Contention List中那些有资格成为候选竞争者的线程被移动到Entry List中;(看来Contention List和Entry List联合组成等待队列)在任意时刻最多只有一个线程正在竞争锁资源,该线程就叫OnDeck;(所以Entry List里的线程还.原创 2021-07-08 16:29:16 · 156 阅读 · 0 评论 -
volatile、双重校验锁实现对象单例(线程安全)
预备知识:volatile关键字主要作用是保证变量的内存可见性和禁止指令重排序。JMM(Java Memory Model)是 Java 虚拟机规范中所定义的一种内存模型,JMM 定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存中,每个线程都有一个私有的工作内存(或者叫本地内存),工作内存中存储了被该线程使用过的共享变量的副本。线程对变量的所有的操作(读,取)都必须在工作内存中完成,而不能直接读写主内存中的变量。不同线程之间也不能直接访问对方工作内存中的变量,线程间变量的值的传递需要通过主内原创 2021-07-08 15:08:54 · 321 阅读 · 0 评论 -
乐观锁CAS和悲观锁
Java中乐观锁基本都是通过CAS实现的。CAS是一种更新的原子操作,可以理解为,比较当前变量的值是否与它以为的值一样,如果一样说明没有其他线程对它进行修改,则将当前变量的值修改为目标值。这是乐观锁的思想。但如果仅仅如此会有ABA问题,就是说有可能其他线程改过数据又把数据改回去了,但CAS却以为没有线程改过数据。因此加入了版本号控制。悲观锁就是默认会有并发,synchronized就是悲观锁。AQS框架下的锁则是先尝试CAS乐观锁去获取锁,获取不到才转化为悲观锁,比如ReentrantLock。.原创 2021-07-08 00:07:50 · 264 阅读 · 0 评论 -
synchronized锁的四种状态和锁升级过程笔记
synchronized从jdk1.6开始引入了偏向锁和轻量级锁,作为无锁和重量级锁的中间状态。四种状态随着竞争情况加剧逐渐升级,且不可逆,即只能升级不能降级。无锁时存储对象的hashcode、对象的分代年龄、是否为偏向锁的标志(0表示不是偏向锁),无锁的标志位是01;当有一个线程访问同步块时无锁就要升级为偏向锁,偏向锁存储内容为偏向线程ID、偏向时间戳、对象分代年龄、是否偏向锁(1),它的标志位和无锁相同,都是01;当有锁竞争时,也就是并发情况出现的时候,就升级为轻量级锁,而在锁竞争不激烈时,没原创 2021-07-07 23:25:24 · 295 阅读 · 0 评论 -
对切面的returning参数的思考
// 定义一个切面@Aspectpublic class LogAspect{ // 匹配com.owenapp.service.impl包下所有类的、 // 所有方法的执行作为切入点 @AfterReturning(returning="rvt" , pointcut="execution(* com.owen.app.service.impl.*.*(..))") // 声明rvt时指定的类型会限制目标方法必须返回指定类型的值或没有返回值 // 此处将rvt的类型声明为Object,原创 2021-07-04 16:49:47 · 354 阅读 · 0 评论 -
Arrays.sort()与比较器的理解
比如下面的代码,在lambda表达式中的自变量是(a,b),然而在比较时使用的却是sa和sb,它需要把sa与sb的比较结果转化为对a和b的交换操作。我的理解是,当(a,b)->1,即返回1的时候就要执行a和b的位置交换,而返回-1则不交换。注意b和a都是字符串所以当sb<sa,即(b+a)<(a+b)时,sb.compareTo(sa)返回-1,因此保持自变量原顺序(a,b),也就是说此时的(a,b)的顺序保证了(b+a)<(a+b),即组合的字符串ab>ba.当sb&原创 2021-05-23 23:35:11 · 428 阅读 · 0 评论 -
(right+left)/2和left+(right-left)/2在int截断条件下是等价的证明
(int)(right+left)/2={(right+left)/2,if(right+left)is even(right+left)/2−1/2,if(right+left)is odd(int)(right+left)/2=\begin{cases}(right+left)/2,& \text{if}\quad (right+left) \quad \text{is even}\\(right+left)/2-1/2,& \text{if} \quad (原创 2021-03-29 15:38:20 · 395 阅读 · 0 评论 -
二分法中计算(left+right)/2和(left+right+1)/2的index区别的根源
注意(left+right)/2,(left+right+1)/2,当left+right为偶数时,在int的取整下,+1实际上是对整数+1/2,对结果无影响,而当left+right为奇数时,+1所造成的1/2会与奇数中原本被取整丢掉的1/2合并,使得与原结果相比+1...原创 2021-03-29 14:47:40 · 808 阅读 · 0 评论 -
剑指Offer-矩阵中的路径
import java.util.Stack;import java.util.Vector;public class E05 { public static void main(String[] args) { String str = "ABCEHJIGSFCSLOPQADEEMNOEADIDEJFMVCEIFGGS"; char[] matrix = str.toCharArray(); String str2 = "ABCCEIDESEHJONOF"; c.原创 2020-07-09 16:26:23 · 110 阅读 · 0 评论 -
剑指offer-机器人的运动范围
题目描述地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?例如:输入(15,20,20),输出359class Solution { public int movingCount(int threshol原创 2020-07-09 13:13:08 · 87 阅读 · 0 评论 -
Java简单无数据库学生管理系统,和一个bug
写了一个不基于数据库的Java的学生管理系统,发现了一个问题,scanner.next()函数输入中文时会发生NoElementException异常,换成输入英文就好了。经测试,的确就是中英文的问题。(待解决)代码:import java.util.*;public class StudentManager { public static Scanner scanner = ne...原创 2020-03-03 23:02:50 · 411 阅读 · 0 评论 -
java的引用变量赋值问题
剑指offer中的一道题:输入一个链表,反转链表后,输出新链表的表头。其中用到了引用型变量的赋值。代码:import java.util.Stack;public class test4 { public static void main(String[] args) { test4 test=new test4(); ListNode head...原创 2020-02-29 15:29:51 · 698 阅读 · 0 评论 -
java的线程的join()方法
线程的join方法原创 2020-02-18 18:13:37 · 131 阅读 · 0 评论 -
vscode配置Java
vscode配置Java,添加extension时出现缺少jdk的问题,vscode提示跳转到Redhat网页。然而,我们可以有更方便的环境配置管理软件anaconda,将anaconda的路径添加到环境变量中,只需在anaconda中安装openjdk包即可。...原创 2020-01-14 13:01:39 · 456 阅读 · 0 评论