java
文章平均质量分 83
zy_think123
写代码让我学会了思考,而思考又教会了我写代码。我不保证我写的每个地方都是对的,但是至少可以保证我是思考过的。我的努力加上你的,解个bug总没有问题吧!
展开
-
日志这么记,再也没有背过锅
不知道你有没有经历过被日志支配的恐惧?我就经历过,以前在服务器上要找到一个请求经过所有链路的日志,并串联起来发现真的好难,而且有了日志还没用,最好还有有参数,有响应可以串联起来整个业务逻辑,最大程度进行场景复原,那段找日志的时光真是不堪回首,令人难忘,好在后来我离开了再没去服务器上看过日志了。针对这种场景,怎么解呢?针对每次请求如果我们生成一个id,每次打印日志的时候都把这个id打印出来,那么当我们搜索每次请求的时候,根据这个id进行搜索就行了,本文也是基于这个思路来实现这个功能的。请求链路clien原创 2021-04-09 16:52:36 · 212 阅读 · 0 评论 -
创建线程的几种主流方式
继承Thread类继承Thread类,并重写它的run方法,就可以创建一个线程了,当然线程是如何真正被启动,可以参考我之前的 为什么start方法才能启动线程,而run不行?class ThinkThread extends Thread { @Override public void run() { System.out.println("think123"); }}new ThinkThread().start();实现Runnable接口 new Thread原创 2021-01-22 13:05:40 · 331 阅读 · 0 评论 -
Java并发容器那么多,应该怎么选?
我们先来看看有哪些并发容器这么多容器,我们该怎么选? 虽然不能全要,但是我们可以都了解一下,然后挑选适合自己的。并发下的Map我们都知道不能再并发场景下使用HashMap,因为在JDK7之前,在并发场景下使用 HashMap 会出现死循环,从而导致 CPU 使用率居高不下,而扩容是导致死循环的主要原因。虽然 Java 在 JDK8 中修复了 HashMap 扩容导致的死循环问题,但在高并发场景下,依然会有数据丢失以及不准确的情况出现。HashMap扩容出现死循环的分析可以查看我之前的文章为了保证原创 2021-01-14 10:25:26 · 259 阅读 · 0 评论 -
一个比读写锁更快的锁----StampedLock
简介ReentrantReadWriteLock支持读写锁,StampedLock支持写锁、悲观锁读和乐观读(无锁)。其中写锁、悲观读锁的语义和ReentrantReadWriteLock中的写锁、读锁语义一样,都是允许多个线程同时获取悲观锁读,但是只允许一个线程获取写锁,写锁和悲观读锁是互斥的。不同的是:StampedLock 里的写锁和悲观读锁加锁成功之后,都会返回一个 stamp;然后解锁的时候,需要传入这个 stamp。以下为官方使用例子public class Point { pri原创 2020-12-25 18:53:39 · 145 阅读 · 0 评论 -
Java中的读写锁是如何实现的?
针对读多写少的场景,Java提供了另外一个实现Lock接口的读写锁ReentrantReadWriteLock(RRW),之前分析过ReentrantLock是一个独占锁,同一时间只允许一个线程访问。而 RRW 允许多个读线程同时访问,但不允许写线程和读线程、写线程和写线程同时访问。读写锁内部维护了两个锁,一个是用于读操作的ReadLock,一个是用于写操作的 WriteLock。读写锁遵守以下三条基本原则允许多个线程同时读共享变量;只允许一个线程写共享变量;如果一个写线程正在执行写操作,此时原创 2020-12-17 11:09:35 · 884 阅读 · 0 评论 -
面试官问我AQS中的PROPAGATE有什么用?
之前分析过AQS的源码,但只分析了独占锁的原理。而刚好我们可以借助Semaphore来分析共享锁。如何使用Semaphorepublic class SemaphoreDemo { public static void main(String[] args) { // 申请共享锁数量 Semaphore sp = new Semaphore(3); for(int i = 0; i < 5; i++) { new Thread(() -> {原创 2020-12-03 15:48:21 · 1216 阅读 · 3 评论 -
好烦,面试官逮着我问ReentrantLock的这几个问题!
公平锁和非公平锁的区别?之前分析AQS的时候,了解到AQS依赖于内部的两个FIFO队列来完成同步状态的管理,当线程获取锁失败的时候,会将当前线程以及等待状态等信息构造成Node对象并将其加入同步队列中,同时会阻塞当前线程。当释放锁的时候,会将首节点的next节点唤醒(head节点是虚拟节点),使其再次尝试获取锁。同样的,如果线程因为某个条件不满足,而进行等待,则会将线程阻塞,同时将线程加入到等待队列中。当其他线程进行唤醒的时候,则会将等待队列中的线程出队加入到同步队列中使其再次获得执行权。按照我们的分原创 2020-11-26 16:58:25 · 210 阅读 · 0 评论 -
那些去请求锁的线程都怎样了?
不知道你有没有想过,那些去申请锁的线程都怎样了?有些可能申请到了锁,马上就能执行业务代码。但是如果有一个锁被很多个线程需要,那么这些线程是如何被处理的呢?今天我们走进synchronized 重量级锁,看看那些没有申请到锁的线程都怎样了。ps: 如果你不想看分析结果,可以拉到最后,末尾有一张总结图,一图胜千言之前文章分析过synchroinzed中锁的优化,但是如果存在大量竞争的情况下,那么最终还是都会变成重量级锁。所以我们这里开始直接分析重量级锁的代码。申请锁在ObjectMonitor::en原创 2020-11-12 14:57:57 · 233 阅读 · 0 评论 -
拥抱Kubernetes,再见了,SpringBoot cronjob
项目开发中总是需要执行一些定时任务,比如定时处理数据之后发送邮件,定时更新缓存等等。Java定时任务基于 java.util.Timer 定时器,实现类似闹钟的定时任务使用 Quartz、elastic-job、xxl-job 等开源第三方定时任务框架,适合分布式项目应用使用 Spring 提供的一个注解: @Schedule项目框架使用的是SpringBoot,所以之前定时任务使用的是SpringBoot中的@Scheduled。可是这种方式并不适合我们现在的cloud环境,为了更加cloud n原创 2020-11-06 18:54:01 · 469 阅读 · 1 评论 -
这样的Synchronized,怎么可能慢?
模板解释器我们都知道Java之所以可以一次编译到处运行,完全是因为字节码的原因,字节码就相当于中间层屏蔽了底层细节。但是想要在机器执行,最终还是要翻译成机器指令。而JVM是通过C/C++来编写的,Java程序编译后,会产生很多字节码指令,每一个字节码指令在JVM底层执行的时候又会编程一堆C代码,这一堆C代码在编译之后又会编程很多的机器指令,这样我们的java代码到最终执行的机器指令那一层,所产生的机器指令时指数级的,这也就导致了Java执行效率低下。早期的JVM是因为解释执行慢而被人诟病,那么有没有办原创 2020-10-27 13:16:40 · 892 阅读 · 0 评论 -
Java对象在内存中的布局 没有你想的那么神秘
写在前面Java是用C++写的,所以java对象最终会映射到c++中的某个对象,用这个对象可以描述所有Java对象。而我们所熟知的synchronized锁的优化就是基于这个对象来实现的。对象在内存中的布局Java对象在被创建的时候,在内存分配完成后,虚拟机需要对对象进行必要设置, 例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头(Object Header)中。根据虚拟机当前运行状态的不同,如是否启用偏向锁等对象头会有不同的原创 2020-09-27 11:06:20 · 238 阅读 · 0 评论 -
HBase Scan命令详解
hbase中scan命令是我们经常使用到的,而filter的作用尤其强大。这里简要的介绍下scan下filter命令的使用.插入scan命令需要的数据这里模拟了部分微博评论的数据,然后使用代码插入数据到hbase,代码就不列出来了比较简单。public class Comment { //1-->普通文章,2--->热点文章 Integer articleType; //文章id String articleId; String userId;原创 2020-09-16 14:24:38 · 13607 阅读 · 0 评论 -
三年前,我因为这道面试题怼了面试官
三年前,我做了一道关于try-catch-finnaly的面试题,但我做错了,当时面试官问我为啥错了,我告诉它,我平常不会写这么傻逼的代码,然后面试官就没有问我了。。。。最近看到其他面试的童鞋,又让我想起了这道题,刚好也试着分析下。我们知道Java虚拟机栈是线程私有的,它的生命周期与线程相同。虚拟机栈是Java虚拟机运行时数据区一部分,它描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程就原创 2020-09-03 11:11:41 · 159 阅读 · 0 评论 -
看完这篇,我不信你对String.intern()还有疑惑
常量池Java虚拟机管理的内存包含以下几个运行时数据区域方法区与java堆一样,是各个线程共享的内存区域,用于存储已经被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。JDK8之前很多人叫它永久代(这里可以联想下年前代,老年代),是因为当时HotSpot虚拟机的设计团队选择将收集器的分代设计扩展至方法区,或者说使用永久代来实现方法区而已。这样使得HotSpot的垃圾收集器能像管理Java堆一样管理这部分内存。但是对于其他虚拟机实现是不存在这个概念的。运行时常量池(Runt原创 2020-08-28 12:24:52 · 322 阅读 · 0 评论 -
从源码分析什么start方法才能启动线程,而run不行?
我们都知道,一个线程直接对应了一个Thread对象,在刚开始学习线程的时候我们也知道启动线程是通过start()方法,而并非run()方法。那这是为什么呢?如果你熟悉Thread的代码的话,你应该知道在这个类加载的时候会注册一些native方法publicclass Thread implements Runnable { /* Make sure registerNatives is the first thing <clinit> does. */ private stati原创 2020-08-07 10:42:09 · 222 阅读 · 0 评论 -
写了这么久代码,我才知道Main线程原来是这样被启动的!
当我们运行Java程序main方法的时候,我们都知道当前线程是main线程Thread.currentThread().getName()那么这个main线程是被谁启动,又是在什么时候被启动的呢?我们通过源码一探究竟。jvm的启动入口是main.c,由于我之前可以在mac上调试jvm了,所以我通过下面的参数进行启动java -Xss512K -XX:+UseConcMarkSweepGC -Xms512M Main arg1=think123&nb原创 2020-07-31 10:22:36 · 586 阅读 · 1 评论 -
费尽九牛二虎之力,终于我成功编译并调试了JVM
最近在看synchronized 锁优化方面的内容,有些地方看起来不是很方便,干脆就编译个源码来看看。在windows上编译由于自己常用的电脑操作系统是win10,所以最开始是想要在win10上编译的,但是一来网上文章太少,二来在windows上编译确实麻烦太多了(windows可以参考深入理解JVM虚拟机这本书),故放弃了。MAC环境准备获取源码OpenJDK源码使用Mercurial管理,如果通过版本库下载,则需要安装Mercurial,我们借助homebrew包管理器来安装brew i原创 2020-07-24 10:18:43 · 1371 阅读 · 0 评论 -
【万字长文】操作系统如何解决并发问题?
在之前的文章中我们讲到过引起多线程bug的三大源头问题(可见性,原子性,有序性问题),java的内存模型(Java Memory Model)可以解决可见性和有序性问题,但是原子性问题如何解决呢?public class Counter { volatile int count; public void add10K() { for(int i = 0; i < 10000; i++) { count++; } } public int get(原创 2020-07-06 17:51:43 · 1054 阅读 · 0 评论 -
Graphql集成SpringMVC和MongoDB
什么是GraphQLGraphQL 是一种用于 API 的查询语言。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。GraphQL 查询不仅能够获得资源的属性,还能沿着资源间引用进一步查询。典型的 REST API 请求多个资源时得载入多个 URL,而 GraphQL 可以通过一次请求就获取你应用所需的所有数据。GraphQL API 基于类型和字段的方式原创 2020-06-19 10:22:50 · 448 阅读 · 0 评论 -
弄明白这三个问题,并发编程不再难
编写正确的程序难,编写正确的并发程序则是难上加难。既然这么难为什么还要并发,单线程执行不好吗?为了快呀,点个链接你愿意等1分钟吗?,别说等一分钟了,要是有个网页让我等超过10秒钟,我就马上要关掉了。我们编写的代码在计算机中运行,那么它肯定会用到计算机中的资源,一般都逃不过cpu、内存以及I/O(文件I/O或者网络I/O等)。但是这三者速度上有极大的差异。CPU的速度远远快于内存,而内存的速度又远远远快于I/O。比喻: CPU速度相当于 火箭,内存速度相当于 高铁,I/O速度相当于 步行。而我们的原创 2020-06-13 09:18:24 · 299 阅读 · 0 评论 -
玩转正则表达式
这是think123的第60篇原创文章正则表达式是一个很强大的模式语言,使用它我们能够解决很多很棘手的问题,有时候使用字符串查找来解决这类问题不是很方便,所以这个时候正则表达式就能帮我们很大的忙。完整的正则表达式由两种字符构成。特殊字符(specialcharacters,比如*)称为“元字符”(metacharacters),其他为“文字”(literal),或者是普通文本字符(normaltext characters).如何理解正则表达式正则表达式是一门语言,同样有着它的语言模式,所以我.原创 2020-06-08 15:18:31 · 215 阅读 · 0 评论 -
对于Http Status Code,我有话说
现在很多项目都是web项目,前后端分离,唯一的交互就是通过restful接口,而当我们请求返回的时候,status code如何返回呢?首先介绍下常用的http status code有哪些。2XX(Success 成功状态码)200 - OK请求成功201 - Created文档创建成功,比如新增一个user成功202 - Accepted请求已被接受,但相应的操作可能尚未完成。这用于后台操作,例如数据库压缩等异步操作4XX(Client Error 客户端错误状态码)400 -原创 2020-06-01 10:24:21 · 771 阅读 · 0 评论 -
为什么零拷贝可以提升Kafka性能?
从操作系统说起计算机系统是由“硬件”和“软件”两大部分组成,计算机硬件包括一个或多个处理器(CPU)、内存、键盘、显示器、磁盘、I/O接口以及其他一些外围设备比如打印机,绘图仪等等。总之,计算机硬件部分是一个由多种电子和机械设备组成的硬件系统。为了让人方便正确使用这些设备,就需要编写若干程序来管理这些设备,正是这些程序组成了计算机的软件系统。软件也可以分为两大类:系统软件和应用软件。人们首先直接在硬件上加载一层程序,用它来管理整个计算机硬件设备以及一些软件信息资源,同时还为用户提供开发应用程序的环境,原创 2020-05-20 10:09:20 · 173 阅读 · 0 评论 -
我只想获取个请求IP,为什么就那么难?
web开发中,经常会获取请求端IP地址,熟悉的同学可能第一时间就想到了String ip = httpServletRequest.getRemoteAddr();如果你的客户端和你的服务器是直连的,中间没有经过任何的代理这样是没有问题,如果你是通过了代理服务器访问了后端服务,那么获取到的ip其实是代理服务器的ip。直连: client --> Server代理: client -...原创 2020-05-08 09:54:43 · 345 阅读 · 0 评论 -
道友,JAXB了解下
什么是JAXBJAXB(Java Architecture for XML Binding简称JAXB)允许Java开发人员将Java类映射为XML表示方式。JAXB提供两种主要特性:将一个Java对象序列化为XML,以及反向操作,将XML解析成Java对象。换句话说,JAXB允许以XML格式存储和读取数据,而不需要程序的类结构实现特定的读取XML和保存XML的代码。注解注解作用域...原创 2020-04-02 10:16:17 · 129 阅读 · 0 评论 -
你的事儿发了!
为什么要避免将敏感信息存储在git中?不要在git仓库中存储任何敏感信息,并且要不惜一切代价这样做,即使仓库是私有的,也不应该将其视为存储敏感信息的安全场所,首先让我们了解为什么它存储敏感信息不安全。git上如果你将你的仓库声明为public的,那么任何一个人都可以访问你仓库的内容,不仅如此,还可以游览仓库中的所有代码,甚至可以运行它。如果你将你的API秘钥存储在仓库中,那么任何人都可以拿到。...原创 2020-04-01 09:54:18 · 347 阅读 · 0 评论 -
我用Squid为Java http请求设置代理
什么是代理服务器代理服务器充当你和Internet之间的网关,就像一个中间人。它实际上是一个中间服务器,可以将用户与它们游览的网站区分开。如果你使用了代理服务器,那么网络流量会通过代理服务器流向你请求的地址。然后该请求通过同一台代理服务器返回,然后代理服务器将从网站接收到的数据转发给你。当然如果仅仅是这样,也没什么必要使用代理服务器,我们直接访问网站岂不更美?现在代理服务器的功能远不只是转...原创 2020-03-31 09:59:46 · 1944 阅读 · 0 评论 -
为什么阿里建议你不要使用Executors来创建线程池?
前言我相信大家在项目中或多或少的都使用过线程,而线程是宝贵的资源,不能频繁的创建,应当给其他任务进行复用,所以就有了我们的线程池。线程池的使用你知道我们如何创建线程池吗?这我当然知道了,JDK主要提供了三种创建线程池的方法Executors.newFixedThreadPool(int nThreads) : 创建固定线程数量的线程池Executors.newSingleThre...原创 2020-03-30 09:33:04 · 1340 阅读 · 0 评论 -
不简单的Java基本数据类型
认识Java中的基本数据类型Java中有8大基本数据类型,它的对应包装类型以及数据范围如下:基本数据类型名称封装数据类型名称所占字节数取值范围booleanBoolean1true/falsebyteByte1-128~127charCharacter20~65535shortShort2-32768~32767intI...原创 2020-03-27 10:23:51 · 138 阅读 · 0 评论 -
你真的会用Java8 Optional吗?
Java8之前我们在写代码的时候,经常会遇到返回null的情况,如果这种情况不加以判断,你就会碰到NullPointerException(NPE)。而在Java8中,Optional类型是一种更好的表示缺少返回值的形式。首先来看一段代码,这可能是以前大多数人的写法private void getIsoCode( User user){ if (user != null) { Ad...原创 2020-03-26 09:36:37 · 143 阅读 · 0 评论 -
你应该知道的wait/notify那点事儿
在Java的Object类中有2个我们不怎么常用(框架中用的更多)的方法:wait()与notify()或notfiyAll(),这两个方法主要用于多线程间的协同处理,即控制线程之间的等待、通知、切换及唤醒。首先了解下线程有哪几种状态,Java的Thread.State中定义了线程的6种状态,分别如下:NEW 未启动的,不会出现在dump文件中(可以通过jstack命令查看线程堆栈)...原创 2020-03-25 09:25:54 · 418 阅读 · 0 评论 -
RESTful资源命名最佳实践
在Rest中,数据的呈现方式叫做资源(Resource)。拥有强大而一致的REST资源命名策略,是最好的设计决策。一个资源可以是单个的也可以是一个集合。比如customers是一个集合,而customer是单个资源。我们可以定义customers这个集合的资源的URI是/customers,而单个customer资源的URI是/customers/{customerId}。资源也可以包含子集合...原创 2020-03-23 09:31:00 · 588 阅读 · 0 评论 -
揭秘,门面日志如何发现具体日志组件
commons-loggingcommons-logging是apache提供的一个通用的日志接口,是为了避免和具体的日志方案直接耦合的一种实现。通过commons-logging用户可以自己选择log4j或者jdk自带的logging作为具体实现。使用commons-logging的代码如下import org.apache.commons.logging.Log;import org....原创 2020-03-20 09:25:26 · 124 阅读 · 0 评论 -
老大喊我用AOP记录下日志
老大喊我记录下API的操作日志,免得前端甩锅,主要记录新增,修改,删除等操作。我想了下就决定用AOP来实现这个功能。由于使用的是SpringBoot,所以首先应该在依赖中引入AOP包。 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spri...原创 2020-03-19 10:12:52 · 117 阅读 · 0 评论 -
正则表达式这样写,提升效率50%
正则表达式引擎(DFA/NFA)NFA 是不确定的有限自动机,也就是说在状态的迁移过程中,下一个状态可能有好几种可能,而对于 DFA 确定有限自动机而言,下一个状态只有一种可能。DFA引擎因为不需要回溯,所以匹配快速,但不支持捕获组,所以也就不支持反向引用和$number这种引用方式,目前使用DFA引擎的语言和工具主要有awk、egrep 和 lex。而NFA又基本上可以分为传统型NFA和P...原创 2020-03-18 09:18:41 · 634 阅读 · 0 评论 -
面试官:如何用LinkedHashMap实现LRU
上一篇文章分析了HashMap的原理,有网友留言想看LinkedHashMap分析,今天它来了。LinkedHashMap是HashMap的子类,在原有HashMap数据结构的基础上,它还维护着一个双向链表链接所有entry,这个链表定义了迭代顺序,通常是数据插入的顺序。上图我只画了链表,其实红黑树节点也是一样的,只是节点类型不一样而已也就是说我们遍历LinkedHashMap的时候,是从...原创 2020-03-17 09:24:12 · 2162 阅读 · 0 评论 -
再也不怕面试官问我JDK8 HashMap了
上一篇文章中提到了ThreadLocalMap是使用开放地址法来解决冲突问题的,而我们今天的主角HashMap是采用了链表法来处理冲突的,什么是链表法呢?在散列表中,每个 “ 桶(bucket)” 或者 “ 槽(slot)” 会对应一条链表,所有散列值相同的元素我们都放到相同槽位对应的链表中。jdk8和jdk7不一样,jdk7中没有红黑树,数组中只挂载链表。而jdk8中在桶容量大于等于64且...原创 2020-03-16 09:35:42 · 175 阅读 · 0 评论 -
我为什么要选择traefik2做网关?
单体架构下图简单展示了单体架构的工作流程单体架构是把所有的模块和功能集中到一起,部署到一台服务器中,这种一把梭的方式,赢了还好,输了就下海干活。如果请求过大,一台机器撑不住,也只能通过添加机器的方式来进行横向扩展。微服务架构微服务架构中我们的应用往往是拆分成不同的模块,取而代之的是多个不同的Service独立部署。他们之间的通信通过http或者rpc等方式,这样每个模块我们就可以独立开发...原创 2020-03-13 09:36:39 · 10966 阅读 · 1 评论 -
Kafka consumer是如何加入consumer group的?
consumer比producer要复杂许多,producer没有组的概念,也不需要关注offset,而consumer不一样,它有组织(consumer group),有纪律(offset)。这些对consumer的要求就会很高,这篇文章就先从consumer如何加入consumer group说起。GroupCoordinator是运行在服务器上的一个服务,负责consumer以及offse...原创 2020-03-12 09:43:52 · 805 阅读 · 0 评论 -
大家都知道HashMap,那你知道开放寻址的ThreadLocalMap吗?
什么是散列散列表(hash table)我们平时也叫它哈希表或者Hash表,它用的是数组支持按照下标随机访问数据的特性,所以散列表其实就是数组的一种扩展,由数组演化而来。可以说,没有数组就没有散列表。比如我们有100件商品,编号没有规律的4位数字,现在我们想要通过编号快速获取商品信息,如何做呢?我们可以将这100件商品信息放到数组里,通过 商品编号%100这样的方式得到一个值,值为1的商品放到...原创 2020-03-11 09:26:06 · 1670 阅读 · 1 评论