自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(37)
  • 问答 (6)
  • 收藏
  • 关注

原创 二叉树的遍历

首先给出二叉树的节点代码 public static class TreeNode { String nodeName ; TreeNode left = null; TreeNode right = null; public TreeNode(String nodeName) { this.nodeName = nodeName; } }先序遍历先看下先序遍历的流程图,接下来的代码也会

2022-05-17 11:50:44 180

原创 从0到1实现自己的阻塞队列

什么是阻塞队列?阻塞队列是这样的一种数据结构,它是一个队列(类似于一个List),可以存放0到N个元素。我们可以对这个队列执行插入或弹出元素操作,弹出元素操作就是获取队列中的第一个元素,并且将其从队列中移除;而插入操作就是将元素添加到队列的末尾。当队列中没有元素时,对这个队列的弹出操作将会被阻塞,直到有元素被插入时才会被唤醒;当队列已满时,对这个队列的插入操作就会被阻塞,直到有元素被弹出后才会被唤醒。在线程池中,往往就会用阻塞队列来保存那些暂时没有空闲线程可以直接执行的任务,等到线程空闲之后再从阻塞

2022-04-07 10:32:59 225

原创 并发编程的艺术读后感

时间片是CPU分配给各个线程的时间,因为时间片非常短,所以CPU通过不停的切换线程执行,让我们感觉多个线程是同时执行的,时间片一般是几十毫秒(ms)。CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这个任务的状态。所以任务从保存到再加载的过程就是一次上下文切换死锁避免死锁的几个常见方法:避免一个线程同时获取多个锁。避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资

2022-03-24 16:23:26 169

原创 算法--刷算法时需要理解的点

链表中环的入口结点思路:设置快慢指针,都从链表头出发,快指针每次走两步,慢指针一次走一步,假如有环,一定相遇于环中某点(结论1)。接着让两个指针分别从相遇点和链表头出发,两者都改为每次走一步,最终相遇于环入口(结论2)。以下是两个结论证明:两个结论:1、设置快慢指针,假如有环,他们最后一定相遇。2、两个指针分别从链表头和相遇点继续出发,每次走一步,最后一定相遇与环入口。证明结论1:设置快慢指针fast和low,fast每次走两步,low每次走一步。假如有环,两者一定会相遇(因为l..

2022-02-11 17:42:49 119

原创 IO多路复用底层原理全解

预备知识:在TCP协议中,建立连接的两个进程各自有一个socket来标识,那么两个socket组成的socket pair就唯一标识一个连接。1.Linux操作系统中断举个例子:比如你在家打游戏,这时候你很饿,点了个外卖,然后你继续打游戏,打到boss剩一丝血的时候,外卖小哥来敲门了,此时你不好意思让外卖小哥一直敲门啊,你就中断了你的游戏,暂停存档了,然后去拿外卖了,回来继续打游戏。上述例子中的外卖小哥来敲门就是系统收到了中断请求,游戏暂停存档去拿外卖就是系统被中断了。先来看一个简单的.

2021-11-13 20:13:05 2326

原创 分布式事务

分布式事务随着互联网的快速发展,软件系统由原来的单体应用转变为分布式应用。分布式系统会把一个应用拆分为可独立部署的多个服务,因此需要服务与服务之间远程协作才能完成事务操作,这种分布式系统环境下由不同的服务之间通过网络远程协作完成事务称之为分布式事务,例如用户注册送积分事务,创建订单减库存事务,银行转账事务等都是分布式事务。我们知道本地事务依赖数据库本身提供的事务特性来实现,因为以下逻辑可以控制本地事务:begin transaction: //1.本地数据库操作:张三减少金额

2021-11-02 14:59:51 750

原创 ELK实现日志全局搜索

ELK:E代表Elasticsearch K代表Kibana L代表LogStash什么是LogStash?Logstash是开源的服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到您最喜欢的"存储库"中。为什么使用LogStash?通常当系统发生故障时,工程师需要登录到各个服务器上,使用grep / sed/ awk 等Linux脚本工具去日志里查找故障原因。在没有日志系统的情况下,首先需要定位处理请求的服务器,如果这台服务器部署了多个实例,则需要去每个应..

2021-11-01 12:17:24 1036

原创 经典的超卖问题

库存超卖是如何产生的?库存为1,但是第一个线程在库存-1的事务未提交的时候被第二个线程读到了,此时第二个线程会认为当前库存仍然是1,然后也会-1.相当于减掉了两次1,最后发生超卖。解决方法:首先在redis里面通过定时任务调度设置秒杀商品的库存,比如1001号商品的库存是10.1.首先通过NGINX反向代理,实现网关2.通过redis的lua脚本 decr 原子性的缩减库存3.大于0的话就会生成一个订单号,将生成的订单号返回,通过订单号轮询获取订单状状态4.生成订..

2021-10-28 01:55:29 259

原创 FutureTask 源码解析

先看一下参数// 表示当前task状态 private volatile int state;// 当前任务尚未执行private static final int NEW = 0;// 当前任务正在结束,尚未完全结束,一种临界状态。private static final int COMPLETING = 1;// 当前任务正常结束private static final int NORMAL = 2;// 当前任务执行过程中发生了异常,内部封装.

2021-10-19 16:04:28 112

原创 SpringBoot自动装配原理

每次问到 Spring Boot, 面试官非常喜欢问这个问题:“讲述一下 SpringBoot 自动装配原理?”。我觉得我们可以从以下几个方面回答:什么是 SpringBoot 自动装配? SpringBoot 是如何实现自动装配的?如何实现按需加载? 如何实现一个 Starter?篇幅问题,这篇文章并没有深入,小伙伴们也可以直接使用 debug 的方式去看看 SpringBoot 自动装配部分的源代码。前言使用过 Spring 的小伙伴,一定有被 XML 配置统治的恐惧。即使 Spr

2021-10-16 17:48:57 112

原创 详解布隆过滤器

海量数据处理以及缓存穿透这两个场景让我认识了 布隆过滤器 ,我查阅了一些资料来了解它,但是很多现成资料并不满足我的需求,所以就决定自己总结一篇关于布隆过滤器的文章。希望通过这篇文章让更多人了解布隆过滤器,并且会实际去使用它!下面我们将分为几个方面来介绍布隆过滤器:什么是布隆过滤器? 布隆过滤器的原理介绍。 布隆过滤器使用场景。 通过 Java 编程手动实现布隆过滤器。 利用 Google 开源的 Guava 中自带的布隆过滤器。 Redis 中的布隆过滤器。1.什么是布隆过滤器?首先

2021-10-14 14:36:39 208

原创 缓存与数据库双写时的数据一致性

先列出所有的解决方案,并且讨论他们的优劣性。1.先更新数据库,后更新缓存2.先更新数据库,后删除缓存3.先更新缓存,后更新数据库4.先删除缓存,后更新数据库1.先更新数据库,后更新缓存这种场景一般是没有人使用的,主要原因是在更新缓存那一步,为什么呢?因为有的业务需求缓存中存在的值并不是直接从数据库中查出来的,有的是需要经过一系列计算来的缓存值,那么这时候后你要更新缓存的话其实代价是很高的。如果此时有大量的对数据库进行写数据的请求,但是读请求并不多,那么此时如果每次写请求都更新一下缓存

2021-10-14 11:22:18 60

原创 浅谈Redis底层原理

Redis的单线程和多线程5.x之前 有两个命令过来 读取io流--->计算值--->写入io流--->读取io流--->计算值--->写入io流这些都是一个线程完成的6.x以后 计算过程还是由一个线程来执行 io的读取和写入有子线程完成,相当于有很多大堂经理负责招待客人 送走客人,但是技师从始至终就一个人。子线程最多8个 4个就差不多了。BIO如何处理多用户访问?public class JamesRedis { static List&...

2021-10-14 04:51:25 144

原创 Redis介绍

简单介绍一下 Redis 呗!简单来说Redis 就是一个使用 C 语言开发的数据库,不过与传统数据库不同的是Redis 的数据是存在内存中的,也就是它是内存数据库,所以读写速度非常快,因此 Redis 被广泛应用于缓存方向。另外,Redis 除了做缓存之外,也经常用来做分布式锁,甚至是消息队列。Redis 提供了多种数据类型来支持不同的业务场景。Redis 还支持事务 、持久化、Lua 脚本、多种集群方案。分布式缓存常见的技术选型方案有哪些?分布式缓存的话,使用的比较多的主要是...

2021-10-12 19:03:35 164

原创 MySql三大日志

MySQL日志 主要包括错误日志、查询日志、慢查询日志、事务日志、二进制日志几大类。其中,比较重要的还要属二进制日志binlog(归档日志)和事务日志redo log(重做日志)和undo log(回滚日志)。redoLogredo log(重做日志)是InnoDB存储引擎独有的,它让MySQL拥有了崩溃恢复能力。比如MySQL实例挂了或宕机了,重启时,InnoDB存储引擎会使用redo log恢复数据,保证数据的持久性与完整性。MySQL中数据是以页为单位,你查询一条记录...

2021-10-12 17:51:10 1082 1

原创 ConcurrentHashMap解析

创建new ConcurrentHashMap();官方建议加上初始化大小(前提你确定大小的情况下),new ConcurrentHashMap(32);比如因为扩容是个很耗费资源的事情。// 传入的初始化数组大小如果是32的话 最终结果是tableSizeFor(32+32/2+1) = 64public ConcurrentHashMap(int initialCapacity) { if (initialCapacity < 0) th..

2021-10-10 04:31:37 280

原创 HashMap底层原理解析

数组数组因为有下标,所以查询很快。但是由于创建的时候内存大小就已经被设定好,所以扩容很麻烦,要将原来的数组复制到一个更大的数组中。链表链表中的每一项都占有各自的内存,他们不是存在于一块内存中,每一项都是靠互相引用链接到一起的。优势:增删很方便,查询麻烦,只能从head元素遍历。散列表整合了上述二者HashHash也称散列、哈希,对应的英文都是Hash。基本原理就是把任意长度的输入,通过Hash算法变成固定长度的输出。这个映射的规则就是对应的Hash算法,而原始数据映射后的二进

2021-10-09 05:26:01 144

原创 AQS的源码解析

先看自己实现的一个AQS的代码示例package mashibing;import java.util.concurrent.locks.AbstractQueuedSynchronizer;public class MyAQSDemo { private MyLock myLock; public MyLock getMyLock() { return new MyLock(); } class MyLock extends Abs..

2021-10-06 19:29:35 152

原创 JVM 垃圾回收

JVM的垃圾回收主要发生在堆内存中,堆内存分为新生代,老年代,新生代分为伊甸园区(Eden),幸存者区1(S0),幸存者区2(S1)大部分情况下(当对象很大的时候,直接进入老年代),对象首先都会在Eden分配,在一次新生代垃圾回收之后,如果对象还存在的话,就会进入S0或者S1,并且对象的年龄会加1,经历这次GC后,Eden和From区会被清空,这个时候,from和to会调换位置,minor Gc一直重复这个过程,最后超过15岁的时候,对象就会进入老年代。为什么大对象要直接进入老年代呢?为

2021-09-28 16:54:22 110

原创 JDK 监控和故障处理工具总结

这些命令在 JDK 安装目录下的 bin 目录下:jps(JVM Process Status): 类似 UNIX 的ps命令。用于查看所有 Java 进程的启动类、传入参数和 Java 虚拟机参数等信息; jstat(JVM Statistics Monitoring Tool): 用于收集 HotSpot 虚拟机各方面的运行数据; jinfo(Configuration Info for Java) : Configuration Info for Java,显示虚拟机配置信息; jm...

2021-09-22 19:54:44 100

原创 创建线程的方式

1: 继承Thread public static void main(String[] args) throws ExecutionException, InterruptedException{ Thread01 thread01 = new Thread01(); thread01.start(); } public static class Thread01 extends Thread { @Override

2021-09-22 02:24:09 135

原创 JVM知识点总结

1.我们自己编写的java代码,是如何在各个平台运行的?java代码通过javac编译成class文件,这种中间码称为字节码,然后通过jvm加载字节码。运行时,解释器将字节码解释为一行行机器码来执行。在程序运行期间,即时编译器会针对热点代码,将该部分代码编译成机器码以获得更高的执行效率。在整个运行过程中,解释器和即时编译器共同作用,使java程序几乎能够达到和编译型语言一样的执行速度。2.什么是类加载器 类加载器就是将javac编译成的class文件,通过加载,生成...

2021-09-10 19:03:53 114

原创 监控全局的异常信息

2021-08-21 21:48:15 46

原创 java并发系列八---ThreadPoolExecutor

线程池的意义在讲解线程池之前,有些读者可能存在这样的疑惑:为什么需要线程池,线程池有什么优越性?关于这个问题,主要从两个角度来进行解答:•减少开销在大部分JVM上,用户线程与操作系统内核线程是1:1的关系,也就是说每次创建回收线程都要进行内核调用,开销较大。那么有了线程池,就可以重复使用线程资源,大幅降低创建和回收的频率。此外,也能一定程度上避免有人在写BUG时,大量创建线程导致资源耗尽。•便于管理线程池可以帮你维护线程ID,线程状态等信息,也可以帮你统计任务执行状态等信息。理解了线程池

2021-08-11 18:27:09 591

原创 Java并发系列七--ConcurrentHashMap

回顾HashMap既然说到HashMap了,那么我们就先来简单总结一下HashMap的重点。1.基本结构HashMap存储的是存在映射关系的键值对,存储在被称为哈希表(数组+链表/红黑树)的数据结构中。通过计算key的hashCode值来确定键值对在数组中的位置,假如产生碰撞,则使用链表或红黑树。需要注意的是,key最好使用不可变类型的对象,否则当对象本身产生变化,重新计算key的hashcode时会与之前的不一样,导致查找错误。由这一点可知,在存储键值对时,我们希望的情况是尽量避免碰撞。那

2021-08-06 18:58:46 370

原创 Java并发系列六:JUC.CountDownLatchCountDownLatch

CountDownLatch作为开发中最常用的组件,也作为面试中被问到的最高频的锁之一,我们有必要来聊聊它的作用以及内部构造。首先尝试用一句话对CountDownLatch进行概括:CountDownLatch基于AQS,它实现了闩锁,在开发中可以将其用作任务计数器。简单直译过来就是:CountDownLatch 这种同步工具允许一条或多条线程等待其他线程中的一组操作完成后,再继续执行。例子好像还是有点拗口,举个简单的例子来辅助理解一下。比如我需要收集七颗龙珠才能召唤神龙,这七颗龙珠没有.

2021-08-05 16:36:05 546

原创 Java并发五---JUC.ReentrantLock

Java并发系列五:JUC.ReentrantLockReentrantLock作为开发中最常用的组件,也作为面试中被问到的最高频的锁之一,我们有必要来聊聊它的作用以及内部构造。首先尝试用一句话对ReentrantLock基于AQS,它实现了公平锁和非公平锁,在开发中可以用它对共享资源进行同步。此外,和syhchronized一样,ReentrantLock支持可重入,但ReentrantLock在调度上更灵活,支持更丰富的功能。这段话中,包含了一些关键词,我将其标注出来,并且形成一张思维导图,这张

2021-08-03 19:24:42 140

原创 JAVA并发四--重中之重AQS

Java并发系列四:重中之重AQS上一期,我们介绍了乐观锁,而乐观锁的本质即是CAS,操作系统提供了支持CAS修改内存值的原子指令,所以乐观锁得以实现。从软件的工程角度去看,虽然底层已经通过CAS实现了乐观锁,Java的底层已经在Unsafe这个类中封装了compareAndSwap方法,支持了对CAS原语的调用,为了使上层更加易用,需要经过进一步的抽象和封装。抽象这个词虽然简单,但私以为要作出高内聚低耦合的抽象绝对是难点。在Java中最著名的并发包就是JUC,其中的组件和日常Java开发息息相关。在

2021-07-30 18:11:16 116

原创 Java并发系列三-乐观锁

乐观与悲观:假设现在有多个线程想要操作同一个资源对象,很多人的第一反应就是使用互斥锁。但互斥锁的同步方式是悲观的,什么是悲观呢?简单来说,就是操作系统将会悲观的认为,如果不严格同步线程调用,那么一定会产生异常,所以互斥锁将会锁定资源,只供一个线程调用,而阻塞其他线程,让其他线程等待,因此,这种同步机制也叫做悲观锁。但悲观锁不是在所用情况下都适用,比如在一些情况下,同步代码块执行的耗时远远小于线程切换的耗时,这样就很不划算。程序员们可能更加希望一些场景下,能够在用户态中对线程的切换进行管理,这样效率更高

2021-07-26 18:30:36 263

原创 由浅入深讲并发----2.悲观锁机制

什么是锁?在并发环境下,会出现多个线程对同一个资源进行争抢的情况,假设A线程对资源进行修改,此时B线程又对资源进行了修改,这种可能会导致数据不一致的问题。为了解决这个问题,很多变成语言引入了锁机制,通过一种抽象的“锁”来对资源进行锁定,当一个线程持有”锁“的时候,其他线程必须等待”锁“,我认为这本质上就是在临界资源上对线程进行一种串行化。Java语言中的锁机制是怎么设计的?在谈锁之前,我们需要简单了解一些Java虚拟机的内存结构。如图2.1JVM运行时内存结构主要包含了五个部分:程序计数器(PC寄

2021-07-23 19:39:13 131

原创 由浅入深讲并发----1.JVM线程模型

有一道面试题非常普遍:“说说线程和进程的区别”。网上流传的答案之一是“线程属于进程”,这个说法是不准确的。Linux线程又被称为“轻量级进程”,这就使很多同学摸不着头脑,那到底是线程还是进程?我们可以这么去理解,“线程”是抽象概念(KLT,内核线程),因为Linux内部没有专门为线程定义的数据结构和调度算法,所以Linux去实现“线程”的方式是“轻量级进程”(LWP,轻量级进程),本质还是进程。只不过加了一个“轻量级”的修饰词 如图1.2“轻量级进程”与“进程”的区别在哪?一个Linux进程拥.

2021-07-23 19:37:16 218

原创 Spring源码分析五 :bean的获取③ - getSingleton

在 Spring 源码分析四 :bean的加载② - doGetBean详解 中,我们知道DefaultSingletonBeanRegistry#getSingleton(java.lang.String, ObjectFactory<?>)这一步创建了bean,如下图:到了这一步,Spring 就基本对 Bean已经创建好了 不抱什么希望了,所以着手开始自己创建bean。本文就来分析 getSingleton(String beanName, ObjectFactory&l.

2021-07-19 19:49:37 349

原创 Spring 源码分析四 :bean的加载② - doGetBean详解

1. 转换 beanNamefinal String beanName = transformedBeanName(name);这一步的目的是为了去除 beanName 的别名,获取bean的真正beanName。这里的name传入的可能是 bean的别名,或者是FactoryBean类型的bean。所以需要一系列的解析,解析包括去除 FactoryBean 的修饰符。也就是说如果 name = “&name” 或者 name = “&&name” 这种多...

2021-07-19 19:14:34 244

转载 Spring 源码分析三 :bean的加载① - doGetBean概述

在 Spring源码分析一:容器的刷新 - refresh() 文章中分析了Spring容器的刷新过程。我们知道了 Spring 在容器刷新的后期 通过调用AbstractApplicationContext#finishBeanFactoryInitialization 方法来实例化了所有的非惰性bean。在这里面就通过 beanFactory.preInstantiateSingletons(); 调用了一个非常关键的方法 AbstractBeanFactory#getBean(java.lang.St

2021-07-16 14:30:31 192

转载 Spring源码分析二:BeanFactoryPostProcessor 的处理

本文分析的方法是 AbstractApplicationContext#invokeBeanFactoryPostProcessors,是 前篇内容的继续部分。本文衍生篇:Spring 源码分析衍生篇八 :ConfigurationClassPostProcessor 上篇Spring 源码分析衍生篇九 :ConfigurationClassPostProcessor 下篇PS : 个人感觉,实现IOC的两个核心后处理器 :ConfigurationClassPostProcessor 解

2021-07-13 20:46:16 363

转载 Spring--自己的理解记录一下

spring中最重要的方法莫过于refresh()方法,所以先搞懂这个方法!@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 准备刷新上下文环境。作用就是初始化一些状态和属性,为后面的工作做准备。 prepareRefresh()...

2021-07-13 18:29:06 148

原创 c++用代码连接打印机并打印图片

HDC hdcPrint; //打印机直流手柄 TCHAR szDevString [120]; //数组为WIN.INI数据 TCHAR * szPrinter,* szDriver; //打印机和驱动程序名称 TCHAR * szPort; //端口名称 TCHAR * nextChar; //检索打印机,打印机驱动程序和 ...

2018-07-20 16:07:29 3874 3

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除