<?xml version="1.0" encoding="utf-8" ?><rss version="2.0"><channel><title><![CDATA[阿凡提煮鸡蛋]]></title><description><![CDATA[发现问题，解决问题，终生学习]]></description><link>https://blog.youkuaiyun.com/zyhui98</link><language>zh-cn</language><generator>https://blog.youkuaiyun.com/</generator><copyright><![CDATA[Copyright &copy; zyhui98]]></copyright><item><title><![CDATA[聚合搜索引擎查询结果的开源项目gosearch]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/128380962</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/128380962</guid><author>zyhui98</author><pubDate>Tue, 20 Dec 2022 10:03:14 +0800</pubDate><description><![CDATA[有段时间对于百度的搜索结果不满意，然后就比对了Google、Sogou、Bing、360、微信公众号、头条搜索对一个词的结果。]]></description><category></category></item><item><title><![CDATA[Guava监视器之Monitor]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/115422732</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/115422732</guid><author>zyhui98</author><pubDate>Sat, 03 Apr 2021 23:17:27 +0800</pubDate><description><![CDATA[前言：对于一个控制锁的业务场景来说，有简单的也有复杂的，最简单的就是判断一个对象是否是null。再复杂点就是对于一个复杂条件的判断。
判断的话如果是一个boolean类型，guava提供了一个监视器类来实现，
相比传统java提供的ReentrantLock,synchronized,他提供了很大的便利性。好，我们一探窥见。
1、Monitor介绍
此类旨在代替ReentrantLock。与使用的代码相比，使用的代码Monitor 不易出错且可读性强ReentrantLock，而不会造成明显的性能损失。
M]]></description><category></category></item><item><title><![CDATA[JUC之玩转Condition]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/115285783</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/115285783</guid><author>zyhui98</author><pubDate>Sun, 28 Mar 2021 19:34:50 +0800</pubDate><description><![CDATA[每期总结一个小的知识点和相关面试题，嘿嘿，又来和大家共同学习了。
GUC中有个类我们用的比较少，但是他确是很多类中不可或缺的成员。他就是Condition。
从字面意思理解就是条件，那条件的话就有true or false。那Condition是起到一个
多线程共享标识位执行阻塞的作用，true 的时候通过， false 的时候等待。
1、Condition的使用
通过下面的一个代码可以看出来如何使用它。
// thread 1
System.out.println(&quot;1 am thread 1 ]]></description><category></category></item><item><title><![CDATA[四种方法实现http服务]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/115120835</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/115120835</guid><author>zyhui98</author><pubDate>Tue, 23 Mar 2021 13:59:54 +0800</pubDate><description><![CDATA[前言：对于微服务来说，如果我们要实现一个web服务，
大部分人可能直接用springboot的spring-boot-starter-web了。
我们知道spring-boot-starter-web默认实现是tomcat，当然你也可以选择其他服务器类型，比如Jetty、Undertow等。
但是如果是一个非springboot项目，该如何实现呢？
这里介绍了下四种实现方式，基于Tomcat、Jetty、JdkHttp、Netty实现内嵌web容器。
Tomcat
依赖的maven坐标：
        &]]></description><category></category></item><item><title><![CDATA[Object.wait() 和 LockSupport.park()的实现原理]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/114856428</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/114856428</guid><author>zyhui98</author><pubDate>Mon, 15 Mar 2021 22:49:28 +0800</pubDate><description><![CDATA[Object.wait()
在进行wait()之前，就代表着需要争夺Synchorized，而Synchronized代码块通过javap生成的字节码中包含monitorenter和monitorexit两个指令。
当在进加锁的时候会执行monitorenter指令，执行该指令可以获取对象的monitor。
同时在执行Lock.wait()的时候也必须持有monitor对象。
LockSupport.park()
操作对象
归根结底，LockSupport调用的Unsafe中的native代码： 
publ]]></description><category></category></item><item><title><![CDATA[公平锁和非公平锁的区别]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/114807172</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/114807172</guid><author>zyhui98</author><pubDate>Sun, 14 Mar 2021 22:25:13 +0800</pubDate><description><![CDATA[在java的锁机制中，公平和非公平的参考物是什么，个人而言觉得是相对产生的结果而立，
简单的来说，如果一个线程组里，能保证每个线程都能拿到锁，那么这个锁就是公平锁。
相反，如果保证不了每个线程都能拿到锁，也就是存在有线程饿死，那么这个锁就是非公平锁。
本文围绕ReenTrantLock来讲。
实现原理
那如何能保证每个线程都能拿到锁呢，队列FIFO是一个完美的解决方案，也就是先进先出，java的ReenTrantLock也就是用队列实现的公平锁和非公平锁。
在公平的锁中，如果有另一个线程持有锁或者有其他线程]]></description><category></category></item><item><title><![CDATA[读写锁的原理]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/114731437</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/114731437</guid><author>zyhui98</author><pubDate>Sat, 13 Mar 2021 10:15:57 +0800</pubDate><description><![CDATA[读写锁的使用
读写锁在 Java 中是 ReentrantReadWriteLock，使用方式是：
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockDemo implements TestDemo {
    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    ReentrantReadWriteLock.Rea]]></description><category></category></item><item><title><![CDATA[线程池源码研究]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/114681558</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/114681558</guid><author>zyhui98</author><pubDate>Thu, 11 Mar 2021 22:11:34 +0800</pubDate><description><![CDATA[前言：第一次写源码分析类文章，有点忐忑，还是硬着头皮上了。
之前几篇线程池文章主要是讲解线程池使用场景，这篇文章我以非代码方式讲解源码，这个估计没人这么干过吧！哈哈。
说实话一打开那种源码贴，不够耐心真心看不完，而且也记不住啊，之前学过一段时间的《记忆法》，最强大脑里面的冠军
袁文魁写了一本书专门讲记忆方法的书，里面说图形记忆是最快，记忆比较难忘的一种记忆方法，如果能加上情绪、味觉
触觉就记的更牢了，这可能和人类历史也有关系，有文字才几千年，没文字的几百万年呢。没文字的时候只能靠
图形、图案来记忆了。
下面]]></description><category></category></item><item><title><![CDATA[volatile原理和使用场景]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/114608443</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/114608443</guid><author>zyhui98</author><pubDate>Tue, 09 Mar 2021 23:48:07 +0800</pubDate><description><![CDATA[volatile 关键字只能用于修饰变量，无法用于修饰方法。并且 volatile 只能保证可见性，但不能保证操作的原子性。
在具体编程中体现为：volatile 只能保证基本类型以及一般对象的引用赋值是线程安全的。
volatile工作原理
为什么 volatile 只能保证可见性，不能保证原子性呢？这跟它的工作原理有关。

线程写 volaitle 变量的步骤为：

改变线程工作内存中 volatile 变量副本的值

将改变后的副本的值从工作内存刷新到主内存



线程读 volatile 变量的步骤]]></description><category></category></item><item><title><![CDATA[synchronized几个小面试点]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/114555102</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/114555102</guid><author>zyhui98</author><pubDate>Mon, 08 Mar 2021 22:58:46 +0800</pubDate><description><![CDATA[synchronized的锁升降级
Java SE1.6为了减少获得锁和释放锁所带来的性能消耗，引入了“偏向锁”和“轻量级锁”，
所以在Java SE1.6里锁一共有四种状态，无锁状态，偏向锁状态，轻量级锁状态和重量级锁状态，它会随着竞争情况逐渐升级。
锁可以升级但不能降级，意味着偏向锁升级成轻量级锁后不能降级成偏向锁。
这种锁升级却不能降级的策略，目的是为了提高获得锁和释放锁的效率。
图解

通俗来讲就是：
偏向锁：仅有一个线程进入临界区
轻量级锁：多个线程交替进入临界区（java没有自旋锁的api，轻量]]></description><category></category></item><item><title><![CDATA[线程池如何传递ThreadLocal]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/114459084</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/114459084</guid><author>zyhui98</author><pubDate>Sat, 06 Mar 2021 21:51:00 +0800</pubDate><description><![CDATA[前言
在做分布式链路追踪系统的时候，需要解决异步调用透传上下文的需求，特别是传递traceId，本文就线程池透传几种方式进行分析。
其他典型场景例子：

分布式跟踪系统 或 全链路压测（即链路打标）

日志收集记录系统上下文

Session级Cache

应用容器或上层框架跨应用代码给下层SDK传递信息


1、JDK对跨线程传递ThreadLocal的支持
首先看一个最简单场景，也是一个错误的例子。
    void testThreadLocal(){
        ThreadLocal&lt;.]]></description><category></category></item><item><title><![CDATA[线程池使用的N种姿势]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/114358116</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/114358116</guid><author>zyhui98</author><pubDate>Thu, 04 Mar 2021 09:16:54 +0800</pubDate><description><![CDATA[线程池在开发中一定会用到，如果能像golang一样，java语言也有协程，也许java程序员就少了一种包袱。
回归正题，我们聊下到底有哪些线程池的使用方式，总结有以下几种。

JDK 内置线程池
Spring线程池
自己魔改封装

1、JDK 内置线程池
常用的有：

我们看下最全的线程池参数，探究为什么阿里规约不建议使用Executors创建默认个数的线程池。
/**
参数【7个】
corePoolSize - 即使空闲时仍保留在池中的线程数，除非设置 allowCoreThreadTimeOut
max]]></description><category></category></item><item><title><![CDATA[线程问题怎么排查]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/114299357</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/114299357</guid><author>zyhui98</author><pubDate>Wed, 03 Mar 2021 09:21:28 +0800</pubDate><description><![CDATA[线程状态的定义
可见在 JDK 中定义的线程状态总共六种，各状态在特定条件下可以转换，其组成了一个线程的生命周期，为了方便理解，对其状态和转换整理成了列表和状态图的形式。



状态
描述



NEW
线程新建但是还没有 start 的时候，即 new Thread()


RUNNABLE
调用了 Thread 的 start() 方法,此时线程可运行，但是也有可能需要等待其他操作系统资源，比如处理器资源，当获取到处理器资源之后，则进入 RUNNING 状态


BLOCKED
当进入同步代码块时，如果]]></description><category></category></item><item><title><![CDATA[线程池怎么做到主动回调]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/114274502</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/114274502</guid><author>zyhui98</author><pubDate>Mon, 01 Mar 2021 23:39:53 +0800</pubDate><description><![CDATA[某些业务场景需要在一个异步操作完成后做一个回调，如果使用Future有个问题，需要主动调用get然后再执行逻辑。但是异步逻辑不知道什么时候结束，所以推荐回调的方式处理比较优雅，本文总结了三种方式可以实现此类需求。
1、CompletableFuture
Future可以明确地完成（设定其值和状态），并且可以被用作CompletionStage ，支持有关的功能和它的完成时触发动作。
当两个或多个线程试图complete ， completeExceptionally ，或cancel一个Completabl]]></description><category></category></item><item><title><![CDATA[线程池执行流程]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/114242628</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/114242628</guid><author>zyhui98</author><pubDate>Mon, 01 Mar 2021 00:19:12 +0800</pubDate><description><![CDATA[ThreadPoolExecutor介绍
通过 ThreadPoolExecutor 创建线程池，API 如下所示：
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                   ]]></description><category></category></item><item><title><![CDATA[什么时候发生GC]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/114165666</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/114165666</guid><author>zyhui98</author><pubDate>Sat, 27 Feb 2021 11:04:52 +0800</pubDate><description><![CDATA[首先gc一个对象在不可达之后，需要在第二次标记之后（finallize执行之后）
什么时候发生yang

eden区满了
from区满了（会把from区和eden区不存活gc掉）
fullgc

什么时候发生old gc

old区满了
cms到达阈值了
新来对象放不了
fullgc
本文由猿必过 YBG 发布



...]]></description><category></category></item><item><title><![CDATA[什么是JIT？怎么优化?]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/114135867</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/114135867</guid><author>zyhui98</author><pubDate>Fri, 26 Feb 2021 15:42:39 +0800</pubDate><description><![CDATA[什么是JIT
JIT 是 just in time 的缩写, 也就是即时编译编译器。
在运行时 JIT 会把翻译过的机器码保存起来，以备下次使用，因此从理论上来说，采用该 JIT 技术可以接近以前纯编译技术。下面我们看看，JIT 的工作过程。

备注：寄存器的使用是编译器的一个非常普遍的优化。寄存器的速度比主存快很多。
怎么优化JIT编译

初级调优：客户模式或服务器模式
中级编译器调优 （-cient，-server 或是-xx:+TieredCompilation）
优化代码缓存 (–XX:Reserv]]></description><category></category></item><item><title><![CDATA[JVM排查问题实战]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/114060578</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/114060578</guid><author>zyhui98</author><pubDate>Thu, 25 Feb 2021 09:32:21 +0800</pubDate><description><![CDATA[CPU 资源占用过高

top 查看当前 CPU 情况，找到占用 CPU 过高的进程 PID=123。

top -H -p123 找出两个 CPU 占用较高的线程，记录下来 PID=2345, 3456 转换为十六进制。

jstack -l 123 &gt; temp.txt 打印出当前进程的线程栈。

查找到对应于第二步的两个线程运行栈，分析代码。


OOM 异常排查
使用 top 指令查询服务器系统状态。

ps -aux|grep java 找出当前 Java 进程的 PID。

jstat -]]></description><category></category></item><item><title><![CDATA[JVM排查问题实战]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/114060507</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/114060507</guid><author>zyhui98</author><pubDate>Thu, 25 Feb 2021 09:31:31 +0800</pubDate><description><![CDATA[CPU 资源占用过高

top 查看当前 CPU 情况，找到占用 CPU 过高的进程 PID=123。

top -H -p123 找出两个 CPU 占用较高的线程，记录下来 PID=2345, 3456 转换为十六进制。

jstack -l 123 &gt; temp.txt 打印出当前进程的线程栈。

查找到对应于第二步的两个线程运行栈，分析代码。


OOM 异常排查
使用 top 指令查询服务器系统状态。

ps -aux|grep java 找出当前 Java 进程的 PID。

jstat -]]></description><category></category></item><item><title><![CDATA[强引用、软引用、弱引用、虚引用以及他们之间和 gc 的关系]]></title><link>https://blog.youkuaiyun.com/zyhui98/article/details/114011118</link><guid>https://blog.youkuaiyun.com/zyhui98/article/details/114011118</guid><author>zyhui98</author><pubDate>Wed, 24 Feb 2021 09:55:06 +0800</pubDate><description><![CDATA[强引用：new 出的对象之类的引用，只要强引用还在，永远不会回收。
强引用是使用最普遍的引用。如果一个对象具有强引用，那垃圾回收器绝不会回收它。如下：
    Object strongReference = new Object();
软引用：引用但非必须的对象，内存溢出异常之前，回收。
软引用可以和一个引用队列(ReferenceQueue)联合使用。如果软引用所引用对象被垃圾回收，JAVA虚拟机就会把这个软引用加入到与之关联的引用队列中。
ReferenceQueue&lt;String&gt; re]]></description><category></category></item></channel></rss>