作者:じ☆ve不哭
> 北京个税退税(北京个税年度汇算)提示 新冠肺炎疫情防控期间,该功能暂缓开通。 今天教在北京地区的提前开通该功能。  受理后大家耐心等待1-2天即可在个税app上申报年度汇算了。
作者:Jason哥哥
大家好才是真的好,广州好滴~
作者:微信小助手
<p style="text-align: center;"><span style="font-size: 14px;letter-spacing: 0.5440000295639038px;text-align: center;max-width: 100%;color: rgb(255, 41, 65);line-height: 22.4px;">(给</span><span style="font-size: 14px;letter-spacing: 0.5440000295639038px;text-align: center;max-width: 100%;line-height: 22.4px;color: rgb(0, 128, 255);">ImportNew</span><span style="font-size: 14px;letter-spacing: 0.5440000295639038px;text-align: center;max-width: 100%;color: rgb(255, 41, 65);line-height: 22.4px;">加星标,提高Java技能)</span></p> <blockquote> <p style="letter-spacing: 0.5440000295639038px;white-space: normal;background-color: rgb(255, 255, 255);max-width: 100%;min-height: 1em;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">来自作者投稿 作者:程序员内点事</span></p> </blockquote> <h4 style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;letter-spacing: normal;">一、为什么要用分布式ID?</span></strong></span></h4> <p><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">在说分布式ID的具体实现之前,我们来简单分析一下为什么用分布式ID?分布式ID应该满足哪些特征?</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <h6 style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;letter-spacing: normal;">1、什么是分布式ID?</span></strong></span></h6> <h6 style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></h6> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">拿MySQL数据库举个栗子:</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">在我们业务数据量不大的时候,单库单表完全可以支撑现有业务,数据再大一点搞个MySQL主从同步读写分离也能对付。</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">但随着数据日渐增长,主从同步也扛不住了,就需要对数据库进行分库分表,但分库分表后需要有一个唯一ID来标识一条数据,数据库的自增ID显然不能满足需求;特别一点的如订单、优惠券也都需要有唯一ID做标识。此时一个能够生成全局唯一ID的系统是非常必要的。那么这个全局唯一ID就叫分布式ID。</span> </section> <section style="line-height: 1.5em;"> <br> </section> <h6 style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;letter-spacing: normal;">2、那么分布式ID需要满足那些条件?</span></strong></span></h6> <h6 style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></h6> <ul class="list-paddingleft-2"> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">全局唯一:必须保证ID是全局性唯一的,基本要求</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">高性能:高可用低延时,ID生成响应要块,否则反倒会成为业务瓶颈</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">高可用:100%的可用性是骗人的,但是也要无限接近于100%的可用性</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">好接入:要秉着拿来即用的设计原则,在系统设计和实现上要尽可能的简单</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">趋势递增:最好趋势递增,这个要求就得看具体业务场景了,一般不严格要求</span> </section></li> </ul> <h4 style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></h4> <h4 style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;letter-spacing: normal;">二、 分布式ID都有哪些生成方式?</span></strong></span></h4> <p><br></p> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">今天主要分析一下以下9种,分布式ID生成器方式以及优缺点?</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <ul class="list-paddingleft-2"> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">UUID</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">数据库自增ID</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">数据库多主模式</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">号段模式</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">Redis</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">雪花算法(SnowFlake)</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">滴滴出品(TinyID)</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">百度 (Uidgenerator)</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">美团(Leaf)</span> </section></li> </ul> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">那么它们都是如何实现?以及各自有什么优缺点?我们往下看</span> <br style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><img src="/upload/78b989db62b4da007dae8c9888f38747.png" data-type="png" data-ratio="0.46944444444444444" data-w="1080" data-backw="578" data-backh="271" style="width: 100%;height: auto;"></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <h5 style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;letter-spacing: normal;">1、基于UUID</span></strong></span></h5> <p><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">在Java的世界里,想要得到一个具有唯一性的ID,首先被想到可能就是UUID,毕竟它有着全球唯一的特性。那么UUID可以做分布式ID吗?答案是可以的,但是并不推荐!</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><pre style="overflow-x:auto;"><code style="font-size: 0.85em;font-family: Consolas, Menlo, Courier, monospace;margin: 0px 0.15em;white-space: pre;overflow: auto;display: block;padding: 0.5em;color: rgb(171, 178, 191);text-size-adjust: none;min-width: 400px;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 44, 52);font-weight: 400;" data-wx-hl-code="public static void main(String[] args) { &lt;br/&gt; String uuid = UUID.randomUUID().toString().replaceAll("-","");&lt;br/&gt; System.out.println(uuid);&lt;br/&gt; }" data-wx-hl-lang="Java" data-wx-hl-style="atom-one-dark"><span style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;"><span style="color: rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span style="color: rgb(198, 120, 221);font-weight: 400;font-style: normal;">static</span> <span style="color: rgb(198, 120, 221);font-weight: 400;font-style: normal;">void</span> <span style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">main</span><span style="font-weight: 400;font-style: normal;">(String[] args)</span> </span>{<br> String uuid = UUID.randomUUID().toString().replaceAll(<span style="color: rgb(152, 195, 121);font-weight: 400;font-style: normal;">"-"</span>,<span style="color: rgb(152, 195, 121);font-weight: 400;font-style: normal;">""</span>);<br> System.out.println(uuid);<br> }</code></pre></span> </section> <section style="line-height: 1.5em;"> <br> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">UUID的生成简单到只有一行代码,输出结果 c2b8c2b9e46c47e3b30dca3b0d447718,但UUID却并不适用于实际的业务需求。</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">像用作订单号UUID这样的字符串没有丝毫的意义,看不出和订单相关的有用信息;而对于数据库来说用作业务主键ID,它不仅是太长还是字符串,存储性能差查询也很耗时,所以不推荐用作分布式ID。</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">优点:</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <ul class="list-paddingleft-2"> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">生成足够简单,本地生成无网络消耗,具有唯一性</span> </section></li> </ul> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">缺点:</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <ul class="list-paddingleft-2"> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">无序的字符串,不具备趋势自增特性</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">没有具体的业务含义</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">长度过长16 字节128位,36位长度的字符串,存储以及查询对MySQL的性能消耗较大,MySQL官方明确建议主键要尽量越短越好,作为数据库主键 UUID 的无序性会导致数据位置频繁变动,严重影响性能。</span> </section></li> </ul> <h5 style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></h5> <h5 style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;letter-spacing: normal;">2、基于数据库自增ID</span></strong></span></h5> <p><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">基于数据库的auto_increment自增ID完全可以充当分布式ID,具体实现:需要一个单独的MySQL实例用来生成ID,建表结构如下:</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><pre style="overflow-x:auto;"><code style="font-size: 0.85em;font-family: Consolas, Menlo, Courier, monospace;margin: 0px 0.15em;white-space: pre;overflow: auto;display: block;padding: 0.5em;color: rgb(171, 178, 191);text-size-adjust: none;min-width: 400px;font-weight: 400;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 44, 52);" data-wx-hl-code="CREATE DATABASE " seq_id="seq_id" table="table" seqid="seqid" amp="amp" bigint="bigint" unsigned="unsigned" not="not" null="null" auto_increment="auto_increment" value="value" char="char" default primary="primary" key="key" engine="MyISAM;&lt;br/&gt;insert" into="into" sequence_id="sequence_id" values="values" data-wx-hl-lang="Java" data-wx-hl-style="atom-one-dark">CREATE DATABASE `SEQ_ID`;<br>CREATE TABLE SEQID.SEQUENCE_ID (<br> <span style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">id <span style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">bigint</span><span style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(<span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">20</span>)</span> unsigned NOT NULL auto_increment,<br> value <span style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">char</span><span style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(<span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">10</span>)</span> NOT NULL <span style="color: rgb(198, 120, 221);font-weight: 400;font-style: normal;">default</span> '',<br> PRIMARY <span style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">KEY</span> <span style="font-weight: 400;font-style: normal;">(id)</span>,<br>) ENGINE</span>=MyISAM;<br><span style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">insert into <span style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">SEQUENCE_ID</span><span style="font-weight: 400;font-style: normal;">(value)</span> <span style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">VALUES</span> <span style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(<span style="color: rgb(152, 195, 121);font-weight: 400;font-style: normal;">'values'</span>)</span></span>;</code></pre></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">当我们需要一个ID的时候,向表中插入一条记录返回主键ID,但这种方式有一个比较致命的缺点,访问量激增时MySQL本身就是系统的瓶颈,用它来实现分布式服务风险比较大,不推荐!</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">优点:</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <ul class="list-paddingleft-2"> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">实现简单,ID单调自增,数值类型查询速度快</span> </section></li> </ul> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">缺点:</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <ul class="list-paddingleft-2"> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">DB单点存在宕机风险,无法扛住高并发场景</span> </section></li> </ul> <h5 style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></h5> <h5 style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;letter-spacing: normal;">3、基于数据库集群模式</span></strong></span></h5> <p><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">前边说了单点数据库方式不可取,那对上边的方式做一些高可用优化,换成主从模式集群。害怕一个主节点挂掉没法用,那就做双主模式集群,也就是两个Mysql实例都能单独的生产自增ID。</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">那这样还会有个问题,两个MySQL实例的自增ID都从1开始,会生成重复的ID怎么办?</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">解决方案:设置起始值和自增步长</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <p style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">MySQL_1 配置: </span><span style="color: rgb(0, 0, 0);font-size: 15px;"></span></p> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><pre style="overflow-x:auto;"><code style="font-size: 0.85em;font-family: Consolas, Menlo, Courier, monospace;margin: 0px 0.15em;white-space: pre;overflow: auto;display: block;padding: 0.5em;color: rgb(171, 178, 191);text-size-adjust: none;min-width: 400px;font-weight: 400;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 44, 52);" data-wx-hl-code="set @@auto_increment_offset = 1; -- 起始值&lt;br/&gt;set @@auto_increment_increment = 2; -- 步长" data-wx-hl-lang="Java" data-wx-hl-style="atom-one-dark">set @<span style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">@auto</span>_increment_offset = <span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">1</span>; -- 起始值<br>set @<span style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">@auto</span>_increment_increment = <span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">2</span>; -- 步长</code></pre></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <p style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">MySQL_2 配置:</span></p> <pre style="overflow-x: auto;"><code style="font-size: 0.85em;font-family: Consolas, Menlo, Courier, monospace;margin: 0px 0.15em;white-space: pre;overflow: auto;display: block;padding: 0.5em;color: rgb(171, 178, 191);text-size-adjust: none;min-width: 400px;font-weight: 400;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 44, 52);" data-wx-hl-code="set @@auto_increment_offset = 2; -- 起始值&lt;br/&gt;set @@auto_increment_increment = 2; -- 步长" data-wx-hl-lang="Java" data-wx-hl-style="atom-one-dark">set @<span style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">@auto</span>_increment_offset = <span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">2</span>; -- 起始值<br>set @<span style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">@auto</span>_increment_increment = <span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">2</span>; -- 步长</code></pre> <p><br></p> <p style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">这样两个MySQL实例的自增ID分别就是:</span></p> <pre style="overflow-x: auto;"><code style="font-size: 0.85em;font-family: Consolas, Menlo, Courier, monospace;margin: 0px 0.15em;white-space: pre;overflow: auto;display: block;padding: 0.5em;color: rgb(171, 178, 191);text-size-adjust: none;min-width: 400px;font-weight: 400;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 44, 52);" data-wx-hl-code="1、3、5、7、9 &lt;br/&gt;2、4、6、8、10" data-wx-hl-lang="Java" data-wx-hl-style="atom-one-dark"><span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">1</span>、<span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">3</span>、<span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">5</span>、<span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">7</span>、<span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">9</span> <br><span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">2</span>、<span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">4</span>、<span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">6</span>、<span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">8</span>、<span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">10</span></code></pre> <p><br></p> <p style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">那如果集群后的性能还是扛不住高并发咋办?就要进行MySQL扩容增加节点,这是一个比较麻烦的事。</span></p> <p style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><img src="/upload/955884084546eee25c874a73e4cad6a7.png" data-type="png" data-ratio="0.5986733001658375" data-w="603" data-backw="578" data-backh="346" style="width: 100%;height: auto;"></span></p> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">从上图可以看出,水平扩展的数据库集群,有利于解决数据库单点压力的问题,同时为了ID生成特性,将自增步长按照机器数量来设置。</span> </section> <section style="line-height: 1.5em;"> <br> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">增加第三台MySQL实例需要人工修改一、二两台MySQL实例的起始值和步长,把第三台机器的ID起始生成位置设定在比现有最大自增ID的位置远一些,但必须在一、二两台MySQL实例ID还没有增长到第三台MySQL实例的起始ID值的时候,否则自增ID就要出现重复了,必要时可能还需要停机修改。</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">优点:</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <ul class="list-paddingleft-2"> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">解决DB单点问题</span> </section></li> </ul> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">缺点:</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <ul class="list-paddingleft-2"> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">不利于后续扩容,而且实际上单个数据库自身压力还是大,依旧无法满足高并发场景。</span> </section></li> </ul> <h5 style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></h5> <h5 style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;letter-spacing: normal;">4、基于数据库的号段模式</span></strong></span></h5> <p><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">号段模式是当下分布式ID生成器的主流实现方式之一,号段模式可以理解为从数据库批量的获取自增ID,每次从数据库取出一个号段范围,例如 (1,1000] 代表1000个ID,具体的业务服务将本号段,生成1~1000的自增ID并加载到内存。表结构如下:</span> <span style="color: rgb(0, 0, 0);font-size: 15px;"> </span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><pre style="overflow-x:auto;"><code style="font-size: 0.85em;font-family: Consolas, Menlo, Courier, monospace;margin: 0px 0.15em;white-space: pre;overflow: auto;display: block;padding: 0.5em;color: rgb(171, 178, 191);text-size-adjust: none;min-width: 400px;font-weight: 400;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 44, 52);" data-wx-hl-code="CREATE TABLE id_generator (&lt;br/&gt; id int(10) NOT NULL,&lt;br/&gt; max_id bigint(20) NOT NULL COMMENT '当前最大id',&lt;br/&gt; step int(20) NOT NULL COMMENT '号段的布长',&lt;br/&gt; biz_type int(20) NOT NULL COMMENT '业务类型',&lt;br/&gt; version int(20) NOT NULL COMMENT '版本号',&lt;br/&gt; PRIMARY KEY (" data-wx-hl-lang="Java" data-wx-hl-style="atom-one-dark"><span style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">CREATE TABLE <span style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">id_generator</span> <span style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(<br> id <span style="color: rgb(198, 120, 221);font-weight: 400;font-style: normal;">int</span>(<span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">10</span>)</span> NOT NULL,<br> max_id <span style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">bigint</span><span style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(<span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">20</span>)</span> NOT NULL COMMENT '当前最大id',<br> step <span style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">int</span><span style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(<span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">20</span>)</span> NOT NULL COMMENT '号段的布长',<br> biz_type <span style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">int</span><span style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(<span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">20</span>)</span> NOT NULL COMMENT '业务类型',<br> version <span style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">int</span><span style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(<span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">20</span>)</span> NOT NULL COMMENT '版本号',<br> PRIMARY <span style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">KEY</span> <span style="font-weight: 400;font-style: normal;">(`id`)</span><br>)</span></code></pre></span> </section> <p><span style="font-size: 15px;text-align: left;"><br></span></p> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">biz_type :代表不同业务类型</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">max_id :当前最大的可用id</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">step :代表号段的长度</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">version :是一个乐观锁,每次都更新version,保证并发时数据的正确性</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.12462908011869436" data-s="300,640" src="/upload/f377d66036293c0d9664f75ab29291c5.png" data-type="png" data-w="1011" style="width: 578px;height: auto;"></p> <p style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <p style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">等这批号段ID用完,再次向数据库申请新号段,对max_id字段做一次update操作,update max_id= max_id + step,update成功则说明新号段获取成功,新的号段范围是(max_id ,max_id +step]。</span></p> <pre style="overflow-x: auto;"><code style="font-size: 0.85em;font-family: Consolas, Menlo, Courier, monospace;margin: 0px 0.15em;white-space: pre;overflow: auto;display: block;padding: 0.5em;color: rgb(171, 178, 191);text-size-adjust: none;min-width: 400px;font-weight: 400;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 44, 52);" data-wx-hl-code="update id_generator set max_id = #{max_id+step}, version = version + 1 where version = # {version} and biz_type = XXX" data-wx-hl-lang="Java" data-wx-hl-style="atom-one-dark">update id_generator set max_id = #{max_id+step}, version = version + <span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">1</span> where version = # {version} and biz_type = XXX</code></pre> <p><br></p> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">由于多业务端可能同时操作,所以采用版本号version乐观锁方式更新,这种分布式ID生成方式不强依赖于数据库,不会频繁的访问数据库,对数据库的压力小很多。</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <h5 style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;letter-spacing: normal;">5、基于Redis模式</span></strong></span></h5> <p><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">Redis也同样可以实现,原理就是利用redis的 incr命令实现ID的原子性自增。</span> <span style="font-size: 15px;text-align: left;"> </span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;text-align: left;"><pre style="overflow-x:auto;"><code style="font-size: 0.85em;font-family: Consolas, Menlo, Courier, monospace;margin: 0px 0.15em;white-space: pre;overflow: auto;display: block;padding: 0.5em;color: rgb(171, 178, 191);text-size-adjust: none;min-width: 400px;font-weight: 400;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 44, 52);" data-wx-hl-code="127.0.0.1:6379> set seq_id 1 // 初始化自增ID为1&lt;br/&gt;OK&lt;br/&gt;127.0.0.1:6379> incr seq_id // 增加1,并返回递增后的数值&lt;br/&gt;(integer) 2" data-wx-hl-lang="Java" data-wx-hl-style="atom-one-dark"><span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">127.0</span>.0.1:<span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">6379</span>> set seq_id <span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">1</span> <span style="color: rgb(92, 99, 112);font-weight: 400;font-style: italic;">// 初始化自增ID为1</span><br>OK<br><span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">127.0</span>.0.1:<span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">6379</span>> incr seq_id <span style="color: rgb(92, 99, 112);font-weight: 400;font-style: italic;">// 增加1,并返回递增后的数值</span><br>(integer) <span style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">2</span></code></pre></span> </section> <section style="line-height: 1.5em;"> <br> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">用redis实现需要注意一点,要考虑到redis持久化的问题。redis有两种持久化方式RDB和AOF</span> </section> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span> </section> <ul class="list-paddingleft-2"> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">RDB会定时打一个快照进行持久化,假如连续自增但redis没及时持久化,而这会Redis挂掉了,重启Redis后会出现ID重复的情况。</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">AOF会对每条写命令进行持久化,即使Redis挂掉了也不会出现ID重复的情况,但由于incr命令的特殊性,会导致Redis重启恢复的数据时间过长。</span> </section></li> </ul> <h5 style="line-height: 1.5em;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></h5> <h5 style="line-height: 1.5em;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;letter-spacing: normal;">6、基于雪花算法(Snowflake)模式</span></strong></span></h5> <p><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;"><br></span></p> <section style="line-height: 1.5em;"> <span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: normal;">雪花算法(Snowflake)是twitter公司内部分布式项目采用的ID生成算法,开源后广受国内大厂的好评,在该算法影响下各大公司相继开发出各具特色的分布式生成器。</span> </section> <section style="line-height: 1.5em;"> <img src="/upload/cd8bb3902870af1de49646697cde0d5f.png" data-type="png" data-ratio="0.3388834476003918" data-w="1021" data-backw="578" data-backh="196" style="width: 100%;height: auto;"> </section> <p><span style="font-size: 15px;color: rgb(0, 0, 0);">Snowflake生成的是Long类型的ID,一个Long类型占8个字节,每个字节占8比特,也就是说一个Long类型占64个比特。</span></p> <p><span style="font-size: 15px;color: rgb(0, 0, 0);"><br></span></p> <p><span style="font-size: 15px;color: rgb(0, 0, 0);">Snowflake ID组成结构�
作者:微信小助手
<h2 style="box-sizing: inherit;font-family: "PingFang SC", "Helvetica Neue", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans CJK SC", Sathu, EucrosiaUPC, Arial, Helvetica, sans-serif;line-height: 1.8;margin-top: 22px;margin-bottom: 16px;font-weight: 600;font-size: 24px;border-width: initial;border-style: none;border-color: initial;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">MQ理论介绍</h2> <h2 style="box-sizing: inherit;font-family: "PingFang SC", "Helvetica Neue", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans CJK SC", Sathu, EucrosiaUPC, Arial, Helvetica, sans-serif;line-height: 1.8;margin-top: 22px;margin-bottom: 16px;font-weight: 600;font-size: 24px;border-width: initial;border-style: none;border-color: initial;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">一、为什么需要消息队列(MQ)</h2> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">主要原因是由于在高并发环境下,同步请求来不及处理,请求往往会发生阻塞。大量的请求到达访问数据库,导致行锁表锁,最后请求线程会堆积过多,从而触发 too many connection错误,引发雪崩效应。我们使用消息队列,通过异步处理请求,从而缓解系统的压力。核心:异步处理、流量削峰、应用解耦</p> <h2 style="box-sizing: inherit;font-family: "PingFang SC", "Helvetica Neue", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans CJK SC", Sathu, EucrosiaUPC, Arial, Helvetica, sans-serif;line-height: 1.8;margin-top: 22px;margin-bottom: 16px;font-weight: 600;font-size: 24px;border-width: initial;border-style: none;border-color: initial;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">二、应用场景</h2> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">异步处理,流量削峰,应用解耦,消息通讯四个场景</p> <h3 style="box-sizing: inherit;font-family: "PingFang SC", "Helvetica Neue", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans CJK SC", Sathu, EucrosiaUPC, Arial, Helvetica, sans-serif;line-height: 1.8;margin-top: 22px;margin-bottom: 16px;font-weight: 600;font-size: 22px;border-width: initial;border-style: none;border-color: initial;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">2.1、异步处理</h3> <ul style="box-sizing: inherit;margin-bottom: 20px;padding-left: 20px;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li style="box-sizing: inherit;line-height: 1.875em;"><p style="box-sizing: inherit;margin-bottom: 8px;line-height: inherit;">场景1:用户注册后,需要发送注册邮件和注册短信。</p></li> <ul style="box-sizing: inherit;margin-bottom: 8px;padding-left: 20px;list-style-type: square;" class="list-paddingleft-2"> <li style="box-sizing: inherit;line-height: 1.875em;"><p>串行方式:将注册信息写入 <code style="box-sizing: inherit;font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;font-size: 13px;margin-right: 3px;margin-left: 3px;padding: 3px 4px;border-width: initial;border-style: none;border-color: initial;border-radius: 4px;background: rgb(246, 246, 246);">数据库</code> 成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端</p></li> </ul> </ul> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.2508710801393728" src="/upload/94a4727191988183e4d98863c1722e35.png" data-type="png" data-w="574" style="box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin-right: auto;margin-left: auto;max-width: 80%;vertical-align: middle;cursor: zoom-in;"></p> <ul style="box-sizing: inherit;margin-bottom: 20px;padding-left: 20px;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li style="box-sizing: inherit;line-height: 1.875em;"><p>并行方式:将注册信息写入数据库成功后,发送注册邮件的同时,发送注册短信。以上三个任务完成后,返回给客户端。与串行的差别是,并行的方式可以提高处理的时间</p></li> </ul> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.5336426914153132" src="/upload/10c3e35a18dd499d461e69350c23375.png" data-type="png" data-w="431" style="box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin-right: auto;margin-left: auto;max-width: 80%;vertical-align: middle;cursor: zoom-in;"></p> <pre style="box-sizing: border-box;font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;font-size: 13px;word-break: break-word;overflow-wrap: normal;overflow: auto;margin-bottom: 20px;padding: 1em;border-width: initial;border-style: none;border-color: initial;border-radius: 4px;line-height: 1.5;background: rgb(246, 246, 246);text-align: left;"><code style="box-sizing: inherit;font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;display: block;border-width: initial;border-style: none;border-color: initial;border-radius: 0px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;overflow: visible;word-break: normal;line-height: 1.5;">假设三个业务节点每个使用50毫秒钟,不考虑网络等其他开销,则串行方式的时间是150毫秒,并行的时间可能是100毫秒。<br>因为CPU在单位时间内处理的请求数是一定的,假设CPU在1秒内吞吐量是100次。则串行方式1秒内CPU可处理的请求量是7次(1000/150)。<br>并行方式处理的请求量是10次(1000/100)<br></code></pre> <ul style="box-sizing: inherit;margin-bottom: 20px;padding-left: 20px;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li style="box-sizing: inherit;line-height: 1.875em;"><p style="box-sizing: inherit;margin-bottom: 8px;line-height: inherit;">小结:如以上案例描述,传统的方式系统的性能(并发量,吞吐量,响应时间)会有瓶颈。如何解决这个问题?</p></li> <ul style="box-sizing: inherit;margin-bottom: 8px;padding-left: 20px;list-style-type: square;" class="list-paddingleft-2"> <li style="box-sizing: inherit;line-height: 1.875em;"><p>引入消息队列,将不是必须的业务逻辑,异步处理。改造后的架构如下:</p></li> </ul> </ul> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.3237639553429027" src="/upload/d5ce9d4814440255f671bbe471793561.png" data-type="png" data-w="627" style="box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin-right: auto;margin-left: auto;max-width: 80%;vertical-align: middle;cursor: zoom-in;"></p> <pre style="box-sizing: border-box;font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;font-size: 13px;word-break: break-word;overflow-wrap: normal;overflow: auto;margin-bottom: 20px;padding: 1em;border-width: initial;border-style: none;border-color: initial;border-radius: 4px;line-height: 1.5;background: rgb(246, 246, 246);text-align: left;"><code style="box-sizing: inherit;font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;display: block;border-width: initial;border-style: none;border-color: initial;border-radius: 0px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;overflow: visible;word-break: normal;line-height: 1.5;"> 按照以上约定,用户的响应时间相当于是注册信息写入数据库的时间,也就是50毫秒。注册邮件,发送短信写入消息队列后,直接返回,<br> 因此写入消息队列的速度很快,基本可以忽略,因此用户的响应时间可能是50毫秒。因此架构改变后,系统的吞吐量提高到每秒20 QPS。<br> 比串行提高了3倍,比并行提高了2倍。<br></code></pre> <ul style="box-sizing: inherit;margin-bottom: 20px;padding-left: 20px;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li style="box-sizing: inherit;line-height: 1.875em;"><p>场景2:订单处理,前端应用将订单信息放到队列,后端应用从队列里依次获得消息处理,高峰时的大量订单可以积压在队列里慢慢处理掉。</p></li> </ul> <h3 style="box-sizing: inherit;font-family: "PingFang SC", "Helvetica Neue", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans CJK SC", Sathu, EucrosiaUPC, Arial, Helvetica, sans-serif;line-height: 1.8;margin-top: 22px;margin-bottom: 16px;font-weight: 600;font-size: 22px;border-width: initial;border-style: none;border-color: initial;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">2.2、流量削峰</h3> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">流量削峰也是消息队列中的常用场景,一般在 <span style="box-sizing: inherit;font-weight: 700;">秒杀或团抢活动</span> 中使用广泛</p> <ul style="box-sizing: inherit;margin-bottom: 20px;padding-left: 20px;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li style="box-sizing: inherit;line-height: 1.875em;"><p style="box-sizing: inherit;margin-bottom: 8px;line-height: inherit;">应用场景:秒杀活动,一般会因为流量过大,导致流量报增,应用挂掉。为解决这个问题,一般需要在应用前端加入消息队列。</p></li> <ul style="box-sizing: inherit;margin-bottom: 8px;padding-left: 20px;list-style-type: square;" class="list-paddingleft-2"> <li style="box-sizing: inherit;line-height: 1.875em;"><p style="box-sizing: inherit;margin-bottom: 8px;line-height: inherit;">可以控制活动的人数</p></li> <li style="box-sizing: inherit;line-height: 1.875em;"><p style="box-sizing: inherit;margin-bottom: 8px;line-height: inherit;">可以缓解短时间内高流量压垮应用</p></li> </ul> </ul> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.2463157894736842" src="/upload/c2d6103a9767489a0427632c913722d0.png" data-type="png" data-w="475" style="box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin-right: auto;margin-left: auto;max-width: 80%;vertical-align: middle;cursor: zoom-in;"></p> <ul style="box-sizing: inherit;margin-bottom: 20px;padding-left: 20px;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li style="box-sizing: inherit;line-height: 1.875em;"><p>让消息不直接到达服务器,而是先让 <span style="box-sizing: inherit;font-weight: 700;">「消息队列」</span> 保存这些数据,然后让下面的服务器每一次都取各自能处理的请求数再去处理,这样当请求数超过服务器最大负载时,就不至于把服务器搞挂了。</p></li> <li style="box-sizing: inherit;line-height: 1.875em;"><p>秒杀业务根据消息队列中的请求信息,再做后续处理</p></li> </ul> <h3 style="box-sizing: inherit;font-family: "PingFang SC", "Helvetica Neue", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans CJK SC", Sathu, EucrosiaUPC, Arial, Helvetica, sans-serif;line-height: 1.8;margin-top: 22px;margin-bottom: 16px;font-weight: 600;font-size: 22px;border-width: initial;border-style: none;border-color: initial;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">2.3、应用解耦</h3> <ul style="box-sizing: inherit;margin-bottom: 20px;padding-left: 20px;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li style="box-sizing: inherit;line-height: 1.875em;"><p>场景说明:用户下单后,订单系统需要通知库存系统。传统的做法是,订单系统调用系统库存接口。</p></li> </ul> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.3865814696485623" src="/upload/1237f403ea57d6b1c46253bc1d7c7284.png" data-type="png" data-w="313" style="box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin-right: auto;margin-left: auto;max-width: 80%;vertical-align: middle;cursor: zoom-in;"></p> <ul style="box-sizing: inherit;margin-bottom: 20px;padding-left: 20px;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li style="box-sizing: inherit;line-height: 1.875em;"><p style="box-sizing: inherit;margin-bottom: 8px;line-height: inherit;">传统模式的缺点:</p></li> <ul style="box-sizing: inherit;margin-bottom: 8px;padding-left: 20px;list-style-type: square;" class="list-paddingleft-2"> <li style="box-sizing: inherit;line-height: 1.875em;"><p style="box-sizing: inherit;margin-bottom: 8px;line-height: inherit;">假如库存系统无法访问,则订单减库存将失败,从而导致订单失败</p></li> <li style="box-sizing: inherit;line-height: 1.875em;"><p style="box-sizing: inherit;margin-bottom: 8px;line-height: inherit;">解决订单系统与库存系统耦合,如何解决?</p><p style="box-sizing: inherit;margin-bottom: 8px;line-height: inherit;">引入消息队列后的方案:</p></li> </ul> </ul> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.5065963060686016" src="/upload/150c9642aa125c776494bbc9fb43d300.png" data-type="png" data-w="379" style="box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin-right: auto;margin-left: auto;max-width: 80%;vertical-align: middle;cursor: zoom-in;"></p> <pre style="box-sizing: border-box;font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;font-size: 13px;word-break: break-word;overflow-wrap: normal;overflow: auto;margin-bottom: 20px;padding: 1em;border-width: initial;border-style: none;border-color: initial;border-radius: 4px;line-height: 1.5;background: rgb(246, 246, 246);text-align: left;"><code style="box-sizing: inherit;font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;display: block;border-width: initial;border-style: none;border-color: initial;border-radius: 0px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;overflow: visible;word-break: normal;line-height: 1.5;">订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功<br>库存系统:订阅下单的消息,采用<span style="box-sizing: inherit;color: rgb(215, 58, 73);">pub</span>/sub(发布/订阅)的方式,获取下单信息,库存系统根据下单信息,进行库存操作<br></code></pre> <ul style="box-sizing: inherit;margin-bottom: 20px;padding-left: 20px;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li style="box-sizing: inherit;line-height: 1.875em;"><p>假如:在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入信息队列就不再关心其他后续操作了。实现订单系统与库存系统的应用解耦。</p></li> </ul> <h3 style="box-sizing: inherit;font-family: "PingFang SC", "Helvetica Neue", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans CJK SC", Sathu, EucrosiaUPC, Arial, Helvetica, sans-serif;line-height: 1.8;margin-top: 22px;margin-bottom: 16px;font-weight: 600;font-size: 22px;border-width: initial;border-style: none;border-color: initial;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">2.4、日志处理</h3> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">日志处理是将消息队列用在日志处理中,比如Kafka的应用,解决大量日志传输的问题。架构简化如下</p> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.22937625754527163" src="/upload/93ea5be56e55d5d185892a456723ba12.png" data-type="png" data-w="497" style="box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin-right: auto;margin-left: auto;max-width: 80%;vertical-align: middle;cursor: zoom-in;"></p> <ul style="box-sizing: inherit;margin-bottom: 20px;padding-left: 20px;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li style="box-sizing: inherit;line-height: 1.875em;"><p style="box-sizing: inherit;margin-bottom: 8px;line-height: inherit;">日志采集客户端,负载日志数据采集,定时写入Kafka队列</p></li> <li style="box-sizing: inherit;line-height: 1.875em;"><p style="box-sizing: inherit;margin-bottom: 8px;line-height: inherit;">Kafka消息队列,负载日志数据的接收,储存和转发</p></li> <li style="box-sizing: inherit;line-height: 1.875em;"><p style="box-sizing: inherit;margin-bottom: 8px;line-height: inherit;">日志处理应用:订阅并消费Kafka队列中的日志数据</p></li> </ul> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.36570561456752654" src="/upload/50f35c623110ce558d3e135fa8cdc517.png" data-type="png" data-w="659" style="box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin-right: auto;margin-left: auto;max-width: 80%;vertical-align: middle;cursor: zoom-in;"></p> <ul style="box-sizing: inherit;margin-bottom: 20px;padding-left: 20px;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li style="box-sizing: inherit;line-height: 1.875em;"><p>(1) Kafka:接收用户日志的消息队列</p></li> <li style="box-sizing: inherit;line-height: 1.875em;"><p>(2) Logstash:做日志解析,统一成JSON 输出给Elasticsearch</p></li> <li style="box-sizing: inherit;line-height: 1.875em;"><p>(3)Kibana:基于Elasticsearch 的数据可视化组件,超强的数据可视化能力是众多公司选择Elkstack的重要原因</p></li> </ul> <h3 style="box-sizing: inherit;font-family: "PingFang SC", "Helvetica Neue", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans CJK SC", Sathu, EucrosiaUPC, Arial, Helvetica, sans-serif;line-height: 1.8;margin-top: 22px;margin-bottom: 16px;font-weight: 600;font-size: 22px;border-width: initial;border-style: none;border-color: initial;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">2.5、消息通讯</h3> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">消息通讯是指,消息队列一般都内置了高效的通信机制就,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等。</p> <ul style="box-sizing: inherit;margin-bottom: 20px;padding-left: 20px;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li style="box-sizing: inherit;line-height: 1.875em;"><p>点对点通讯:</p></li> </ul> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.25842696629213485" src="/upload/e2c5c3df94bb0226654d2f5d85199555.png" data-type="png" data-w="445" style="box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin-right: auto;margin-left: auto;max-width: 80%;vertical-align: middle;cursor: zoom-in;"></p> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">客户端A和客户端B使用同一队列,进行消息通讯。</p> <ul style="box-sizing: inherit;margin-bottom: 20px;padding-left: 20px;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li style="box-sizing: inherit;line-height: 1.875em;"><p>聊天室通讯:</p></li> </ul> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.27740492170022374" src="/upload/11097900a2b82474e864fe8616765ffe.png" data-type="png" data-w="447" style="box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin-right: auto;margin-left: auto;max-width: 80%;vertical-align: middle;cursor: zoom-in;"></p> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">客户端A,客户端B,客户端N订阅同一主题,进行消息发布和接收。实现类似聊天室效果。以上实际是消息队列的两种消息模式,点对点或发布订阅模式。</p> <h2 style="box-sizing: inherit;font-family: "PingFang SC", "Helvetica Neue", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans CJK SC", Sathu, EucrosiaUPC, Arial, Helvetica, sans-serif;line-height: 1.8;margin-top: 22px;margin-bottom: 16px;font-weight: 600;font-size: 24px;border-width: initial;border-style: none;border-color: initial;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">3、衡量指标</h2> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">我们从服务性能、数据存储、集群结构三个方面去对比,选择适合自己项目的消息中间件</p> <table> <thead style="box-sizing: inherit;background: rgb(248, 248, 248);"> <tr style="box-sizing: inherit;background-color: rgb(255, 255, 255);"> <th style="box-sizing: inherit;background-color: rgb(248, 248, 248);padding: 4px 8px;border-top-width: 1px;border-top-color: rgb(221, 221, 221);"><span style="box-sizing: inherit;">特性</span></th> <th style="box-sizing: inherit;background-color: rgb(248, 248, 248);padding: 4px 8px;border-top-width: 1px;border-top-color: rgb(221, 221, 221);"><span style="box-sizing: inherit;">ActiveMQ</span></th> <th style="box-sizing: inherit;background-color: rgb(248, 248, 248);padding: 4px 8px;border-top-width: 1px;border-top-color: rgb(221, 221, 221);" width="116"><span style="box-sizing: inherit;">RabbitMQ</span></th> <th style="box-sizing: inherit;background-color: rgb(248, 248, 248);padding: 4px 8px;border-top-width: 1px;border-top-color: rgb(221, 221, 221);" width="137"><span style="box-sizing: inherit;">RocketMQ</span></th> <th style="box-sizing: inherit;background-color: rgb(248, 248, 248);padding: 4px 8px;border-top-width: 1px;border-top-color: rgb(221, 221, 221);" width="87"><span style="box-sizing: inherit;">Kafka</span></th> </tr> </thead> <tbody style="box-sizing: inherit;"> <tr style="box-sizing: inherit;"> <td style="box-sizing: inherit;padding: 4px 8px;" height="106">单机吞吐量</td> <td style="box-sizing: inherit;padding: 4px 8px;" height="106">万级</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="116" height="106">万级</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="128" height="106">十万级</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="83" height="106">十万级</td> </tr> <tr style="box-sizing: inherit;background-color: rgb(248, 248, 248);"> <td style="box-sizing: inherit;padding: 4px 8px;" height="131">topic 数量对吞吐量的影响</td> <td style="box-sizing: inherit;padding: 4px 8px;" height="131">-</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="111" height="131">-</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="128" height="131">topic 可以达到几百,几千个的级别,吞吐量会有较小幅度的下降</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="83" height="131">topic 从几十个到几百个的时候,吞吐量会大幅度下降</td> </tr> <tr style="box-sizing: inherit;"> <td style="box-sizing: inherit;padding: 4px 8px;">时效性</td> <td style="box-sizing: inherit;padding: 4px 8px;">毫秒级</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="111">微妙级</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="128">毫秒级</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="83">毫秒级</td> </tr> <tr style="box-sizing: inherit;background-color: rgb(248, 248, 248);"> <td style="box-sizing: inherit;padding: 4px 8px;">可用性</td> <td style="box-sizing: inherit;padding: 4px 8px;">高</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="111">高</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="128">非常高,分布式架构</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="83">非常高,分布式架构</td> </tr> <tr style="box-sizing: inherit;"> <td style="box-sizing: inherit;padding: 4px 8px;">消息可靠性</td> <td style="box-sizing: inherit;padding: 4px 8px;">有较低的概率丢失数据</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="111">-</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="128">经过参数优化配置,可以做到 0 丢失</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="83">经过参数优化配置,消息可以做到 0 丢失</td> </tr> <tr style="box-sizing: inherit;background-color: rgb(248, 248, 248);"> <td style="box-sizing: inherit;padding: 4px 8px;">功能支持</td> <td style="box-sizing: inherit;padding: 4px 8px;">完善</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="111">并发能力很强,性能极其好,延时很低</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="128">MQ 功能较为完善,还是分布式的,扩展性好</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="83">功能较为简单,主要支持简单的 MQ 功能,在大数据领域的实时计算以及日志采集被大规模使用,是事实上的标准</td> </tr> <tr style="box-sizing: inherit;"> <td style="box-sizing: inherit;padding: 4px 8px;">优劣势总结</td> <td style="box-sizing: inherit;padding: 4px 8px;">非常成熟,功能强大;偶尔会有较低概率丢失消息;社区不活跃了</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="111">性能极其好,延时很低;功能完善;提供管理界面;社区比较活跃;吞吐量较低;使用 erlang 开发源码阅读不方便;</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="128">接口简单易用;吞吐量高;分布式扩展方便;社区还算活跃;经过双 11 的考验</td> <td style="box-sizing: inherit;padding: 4px 8px;" width="83">MQ 功能比较少;吞吐量高;分布式架构;可能存在消息重复消费问题;主要适用大数据实时计算以及日志收集;</td> </tr> </tbody> </table> <h2 style="box-sizing: inherit;font-family: "PingFang SC", "Helvetica Neue", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans CJK SC", Sathu, EucrosiaUPC, Arial, Helvetica, sans-serif;line-height: 1.8;margin-top: 22px;margin-bottom: 16px;font-weight: 600;font-size: 24px;border-width: initial;border-style: none;border-color: initial;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">4、AvctiveMQ和RabbitMQ</h2> <h3 style="box-sizing: inherit;font-family: "PingFang SC", "Helvetica Neue", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans CJK SC", Sathu, EucrosiaUPC, Arial, Helvetica, sans-serif;line-height: 1.8;margin-top: 22px;margin-bottom: 16px;font-weight: 600;font-size: 22px;border-width: initial;border-style: none;border-color: initial;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">4.1、ActiveMQ</h3> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><span style="box-sizing: inherit;font-weight: 700;">特点:</span></p> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"> 早期主流的消息中间件,包括ZeroMQ,但是这几年使用的很少了,主要在长期维护的项目中使用。API丰富,本身很成熟但是在高并发、大数据</p> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">环境下的性能不够出色,主要试用于中小型项目,有较低的概率丢失数据,最主要是的,官方现在维护的频率一直在降低,好几个月才发布一个版本。</p> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><span style="box-sizing: inherit;font-weight: 700;">架构:</span></p> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"> 1、Master-Slave模式,通过Zookeeper实现节点切换和故障转移</p> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"> 2、NetWork模式,相当于多套Master-Slave模式,通过NetWork网关进行集成</p> <h3 style="box-sizing: inherit;font-family: "PingFang SC", "Helvetica Neue", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans CJK SC", Sathu, EucrosiaUPC, Arial, Helvetica, sans-serif;line-height: 1.8;margin-top: 22px;margin-bottom: 16px;font-weight: 600;font-size: 22px;border-width: initial;border-style: none;border-color: initial;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">4.2、RabbitMQ</h3> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">RabbitMQ 是使用 Erlang 语言开发的开源消息队列系统。基于AMQP协议来实现的。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布与订阅)、可靠性、安全。</p> <p style="box-sizing: inherit;margin-bottom: 20px;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">AMQP协议:更多的用在企业系统内,对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量的要求还在其次场景。</p> <p style="box-sizing: inherit;line-height: inherit;font-family: -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">好处在于可以支撑高并发、高吞吐、性能很高,同时有非常完善便捷的后台管理界面可以使用。另外,他还支持集群化、高可用部署架构、消息高可靠支持,功能较为完善。</p> <p><span style="font-size: 12px;"></span></p> <blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="54" data-source-title=""> <section class="js_blockquote_digest"> <section> <span style="font-size: 12px;">来源:</span> <span style="font-size: 12px;">https://my.oschina.net/tingqianyunluo/blog/3229444</span> </section> </section> </blockquote> <p><br></p> <p><span style="font-size: 12px;"><img src="/upload/dc8e3642ddbd4929ec2f7ede5eacac04.png" data-type="png" data-ratio="0.4875207986688852" data-w="601" style=" top: auto;left: auto;margin: 0px;right: auto;bottom: auto; "></span><br></p>
作者:微信小助手
<blockquote style="color: rgba(0, 0, 0, 0.5);max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="margin-top: 15px;max-width: 100%;min-height: 1em;line-height: normal;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 12px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">来源:webfe.kujiale.com/spring-could-heart/</em></span></p> </blockquote> <p style="margin-top: 20px;margin-bottom: 20px;max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">Spring Cloud 是一个基于 Spring Boot 实现的微服务框架,它包含了实现微服务架构所需的各种组件。</span></p> <p style="margin-top: 20px;margin-bottom: 20px;max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">注:Spring Boot 简单理解就是简化 Spring 项目的搭建、配置、组合的框架。因为与构建微服务本身没有直接关系,所以本文不对 Spring Boot 进行展开。</span></p> <p style="margin-top: 20px;margin-bottom: 20px;max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">另外本文有一些例子涉及到 Spring 和 Spring Boot,建议先了解一下 Spring 和 Spring Boot 再阅读本文。</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin-top: 20px;margin-bottom: 20px;max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">本文的阅读对象主要是没有接触过服务架构,想对其有一个宏观的了解的同学。</span></strong></span></p> <p style="margin-top: 20px;margin-bottom: 20px;max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">本文将从 Spring Cloud 出发,分两小节讲述微服务框架的「五脏六腑」:</span></p> <ul class="list-paddingleft-2" style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;"> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">第一小节「服务架构」旨在说明的包括两点,一服务架构是什么及其必要性;二是服务架构的基本组成。为什么第一节写服务架构而不是微服务架构呢?原因主要是微服务架构本身与服务架构有着千丝万缕的关系,服务架构是微服务架构的根基。</span></p></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">第二小节「五脏六腑」则将结合 Spring Cloud 这个特例来介绍一个完整的微服务框架的组成。</span></p></li> </ul> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(171, 25, 66);font-size: 18px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">「服务架构」</strong></span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin-top: 20px;margin-bottom: 20px;max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">为了方便理解,我先讲一个小故事:(改编自一知乎答主)<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></p> <p style="margin-top: 20px;margin-bottom: 20px;max-wid
作者:微信小助手
<p style="white-space: normal;max-width: 100%;min-height: 1em;text-align: center;"><span style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;max-width: 100%;white-space: pre-wrap;font-size: 14px;color: rgb(255, 41, 65);line-height: 22.4px;box-sizing: border-box !important;overflow-wrap: break-word !important;">(给</span><span style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;max-width: 100%;white-space: pre-wrap;font-size: 14px;line-height: 22.4px;color: rgb(0, 128, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">前端大全</span><span style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;max-width: 100%;white-space: pre-wrap;font-size: 14px;color: rgb(255, 41, 65);line-height: 22.4px;box-sizing: border-box !important;overflow-wrap: break-word !important;">加星标,提升前端技能</span><span style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;max-width: 100%;white-space: pre-wrap;color: rgb(255, 41, 65);font-size: 14px;line-height: 22.4px;box-sizing: border-box !important;overflow-wrap: break-word !important;">)</span></p> <blockquote style="white-space: normal;"> <p><span style="font-size: 14px;">作者:code秘密花园 公号 / ConardLi (本文来自作者投稿)</span></p> </blockquote> <p style="white-space: normal;"><span style="font-size: 15px;"></span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">苹果公司前不久对 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Safari</code> 浏览器进行一次重大更新,这次更新完全禁用了第三方 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code>,这意味着,默认情况下,各大广告商或网站将无法对你的个人隐私进行追踪。而微软和 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Mozilla</code> 等也纷纷采取了措施禁用第三方 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code>,但是由于这些浏览器市场份额较小,并没有给市场带来巨大的冲击。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">从 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">2017</code> 年截至 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">2019</code> 年底, <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Google</code> 面临的罚款总额已经超过 93 亿欧元,其中一大原因便是侵犯用户数据隐私。迫于巨大压力,<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Google Chrome</code> 官方团队前不久也宣布,为了提升用户隐私和安全,未来两年将完全禁用第三方 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">在完全不能写入三方 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code> 的情况下,将会对前端的数据读写方式,甚至是整个广告行业带来巨大影响。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">Cookie 的意义</span><span style="max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.7284595300261096" data-type="png" data-w="766" src="/upload/bb195fe118d9caf04e3ba5859c70c037.png" style="margin-right: auto;margin-left: auto;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">众所周知,<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">HTTP</code> 协议是无状态的协议,如果你在同一个客户端向服务器发送多次请求,服务器不会知道这些请求来自同一客户端。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">这正是 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">HTTP</code> 协议得以广泛应用的原因,试想一下,如果它是有状态协议,你必须要时刻与服务器建立链接,那么如果连接意外断开,整个会话就会丢失,重新连接之后一般需要从头开始;而如果是无状态协议,使得会话与连接本身独立起来,这样即使连接断开了,会话状态也不会受到严重伤害,保持会话也不需要保持连接本身。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">如果 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">HTTP</code> 协议只是用来访问静态文件,那不会有任何问题,但是如果你要为广大用户提供更好的服务,服务器就需要知道每个请求具体来自于哪个用户,比如你在逛淘宝的时候你只需要登录一次,当你发起一次购买请求,服务器就已经知道你登录过了,不会再让你进行登录。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">所以 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">HTTP</code> 协议需要占用浏览器的一小块存储,存储当前访问用户的一些 ”状态“,然后每次发起 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">HTTP</code> 请求,请求中就会携带这些状态,从而让服务器知道你是谁。<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code> 出现的的意义就是为了解决这个问题,让无状态的 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">HTTP</code> 协议拥有一小块记忆。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">但是, <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code> 一经出现,就成了各大广告和购物网站窥探用户隐私的利器,他们使用第三方 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code> 不断获取你的数据,那么什么第三方 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code> 呢?</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">第三方 Cookie</span><span style="max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">如果是你正常的正在逛着天猫,天猫会把你的信息写入一些 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code> 到 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">.tmall.com</code> 这个域下,然而打开控制台你会看到,并不是所有 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code> 都是 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">.tmall.com</code> 这个域下的,里面还有很多其他域下的 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code> ,这些所有非当前域下的 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code> 都属于第三方 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code>,虽然你可能从来没访问过这些域,但是他们已经悄悄的通过这些第三方 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code>来标识你的信息,然后把你的个人信息发送过去了。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.5868263473053892" data-type="png" data-w="1670" src="/upload/c91b28aaf5bfd239b933be9f2968bcb9.png" style="margin-right: auto;margin-left: auto;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">而 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">.tmall.com</code> 这个域下的 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code> 都属于第一方 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code>,那么为什么还需要第三方 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code> 呢?再打开 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">taobao.com</code>,你会发现你已经不需要再登录了,因为淘宝、天猫都属于阿里旗下的产品,阿里为他们提供统一的登录服务,同时,你的登录信息也会存到这个统一登录服务的域下,所以存到这个域下的 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code> 就成了三方 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">我们再打开已经完全禁用了第三方 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code> 的 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Safari</code>,发现只剩下 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">.tmall.com</code> 这个域下的 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code> 了。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.5922580645161291" data-type="png" data-w="1550" src="/upload/4b443e7cdbb5296f61b6bec180639879.png" style="margin-right: auto;margin-left: auto;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">这时你会发现即使你已经登录了天猫,再访问淘宝也还是需要登录的,你已经无法享用这样的功能了,而三方 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code> 可不仅仅就这么点用途,在 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Web</code> 开发中,三方 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code> 的应用非常之广,下面我们再来具体看几个应用场景:</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">三方Cookie的用途</span><span style="max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">前端日志打点</h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.5942408376963351" data-type="png" data-w="1528" src="/upload/97d4d94f46188767985d08cdf695440a.png" style="margin-right: auto;margin-left: auto;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">大多数 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Web</code> 站点都会引用一些第三方 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">SDK</code> 来进行前端异常或性能监控,这些 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">SDK</code> 会通过一些接口将监控到的信息上传到他们的服务器。一般它们都需要标识每个用户来方便排查问题或者统计 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">UV</code> 数据,所以当你一此请求这个站点的时候,它们可能会在你的站点上 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">set</code> 一个 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code>,后续所有的日志上报请求都会带上这个 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code> 。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">由于一般这些第三方 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">SDK</code> 都是用于监控的通用服务,它们肯定会拥有自己独立的域名,比如 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">log.com</code>,它在你的域名 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">mysite.com</code> 下种下的 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code> 就属于第三方 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;">Cookie</code>。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">广告营销神器 - Facebook Pixel</h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.5204582651391162" data-type="png" data-w="611" src="/upload/17fbd2fb3d4459c381bbb4971c314379.png" style="margin-right: auto;margin-left: auto;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 611px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color:
作者:微信小助手
<section style="display: none;" data-tools="新媒体管家" data-label="powered by xmt.cn"> <br> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="margin-top: -10px;padding-right: 10px;padding-left: 10px;font-size: 16px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;"> <p style="color: black;"><img data-backh="340" data-backw="526" data-ratio="0.6463878326996197" src="/upload/cbee2c8d4ccf2274c7a979a83adcab1a.jpg" data-type="jpeg" data-w="526" style="width: 100%;height: auto;"></p> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: right;"><em style="color: rgb(76, 156, 215);"></em><span style="font-size: 14px;">作者|handaqiang</span></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;margin-top: -10px;"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">大家好,我是Guide哥!这篇文章来自读者的投稿,经过了两次较大的改动,两周的完善终于完成。Java 8新特性见这里:<a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484744&idx=1&sn=9db31dca13d327678845054af75efb74&chksm=cea24a83f9d5c3956f4feb9956b068624ab2fdd6c4a75fe52d5df5dca356a016577301399548&token=1082669959&lang=zh_CN&scene=21#wechat_redirect" style="overflow-wrap: break-word;font-weight: bold;color: rgb(140, 181, 249);border-bottom: 1px solid rgb(140, 181, 249);" data-linktype="2">Java8新特性最佳指南</a> 。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);"><em style="color: rgb(76, 156, 215);">Guide 哥:别人家的特性都用了几年了,我 Java 才出来,哈哈!真实!</em></p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;font-weight: bold;font-size: 22px;border-bottom: 2px solid rgb(89, 89, 89);margin-bottom: 30px;color: rgb(89, 89, 89);"><span style="display: none;"></span><span style="display: inline-block;border-bottom: 2px solid rgb(89, 89, 89);">Java9</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">发布于 2017 年 9 月 21 日 。作为 Java8 之后 3 年半才发布的新版本,Java 9 带 来了很多重大的变化其中最重要的改动是 Java 平台模块系统的引入,其他还有诸如集合、Stream 流</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>Java 平台模块系统<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">Java 平台模块系统,也就是 Project Jigsaw,把模块化开发实践引入到了 Java 平台中。在引入了模块系统之后,JDK 被重新组织成 94 个模块。Java 应用可以通过新增的 jlink 工具,创建出只包含所依赖的 JDK 模块的自定义运行时镜像。这样可以极大的减少 Java 运行时环境的大小。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">Java 9 模块的重要特征是在其工件(artifact)的根目录中包含了一个描述模块的 module-info.class 文 件。 工件的格式可以是传统的 JAR 文件或是 Java 9 新增的 JMOD 文件。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>Jshell<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">jshell 是 Java 9 新增的一个实用工具。为 Java 提供了类似于 Python 的实时命令行交互工具。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">在 Jshell 中可以直接输入表达式并查看其执行结果</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>集合、Stream 和 Optional<span style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 增加 了 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">List.of()</code>、 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">Set.of()</code>、 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">Map.of()</code> 和 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">Map.ofEntries()</code>等工厂方法来创建不可变集合,比如 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">List.of("Java", "C++");</code>、 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">Map.of("Java", 1, "C++", 2)</code>;(这部分内容有点参考 Guava 的味道) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">Stream</code> 中增加了新的方法 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">ofNullable</code>、 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">dropWhile</code>、 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">takeWhile</code> 和 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">iterate</code> 方法。 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">Collectors</code> 中增加了新的方法 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">filtering</code> 和 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">flatMapping</code> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">Optional</code> 类中新增了 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">ifPresentOrElse</code>、 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">or</code> 和 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">stream</code> 等方法 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>进程 API<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">Java 9 增加了 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">ProcessHandle</code> 接口,可以对原生进程进行管理,尤其适合于管理长时间运行的进程</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>平台日志 API 和服务<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">Java 9 允许为 JDK 和应用配置同样的日志实现。新增了 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">System.LoggerFinder</code> 用来管理 JDK 使 用的日志记录器实现。JVM 在运行时只有一个系统范围的 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">LoggerFinder</code> 实例。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">我们可以通过添加自己的 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">System.LoggerFinder</code> 实现来让 JDK 和应用使用 SLF4J 等其他日志记录框架。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>反应式流 ( Reactive Streams )<span style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 在 Java9 中的 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">java.util.concurrent.Flow</code> 类中新增了反应式流规范的核心接口 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> Flow 中包含了 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">Flow.Publisher</code>、 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">Flow.Subscriber</code>、 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">Flow.Subscription</code> 和 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">Flow.Processor</code> 等 4 个核心接口。Java 9 还提供了 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">SubmissionPublisher</code> 作为 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">Flow.Publisher</code> 的一个实现。 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>变量句柄<span style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 变量句柄是一个变量或一组变量的引用,包括静态域,非静态域,数组元素和堆外数据结构中的组成部分等 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 变量句柄的含义类似于已有的方法句柄 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">MethodHandle</code> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 由 Java 类 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">java.lang.invoke.VarHandle</code> 来表示,可以使用类 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">java.lang.invoke.MethodHandles.Lookup</code> 中的静态工厂方法来创建 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">VarHandle</code> 对 象 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>改进方法句柄(Method Handle)<span style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 方法句柄从 Java7 开始引入,Java9 在类 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">java.lang.invoke.MethodHandles</code> 中新增了更多的静态方法来创建不同类型的方法句柄 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>其它新特性<span style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="color: rgb(71, 193, 168);">接口私有方法</strong> :Java 9 允许在接口中使用私有方法 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="color: rgb(71, 193, 168);">try-with-resources 增强</strong> :在 try-with-resources 语句中可以使用 effectively-final 变量(什么是 effectively-final 变量,见这篇文章 http://ilkinulas.github.io/programming/java/2016/03/27/effectively-final-java.html) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="color: rgb(71, 193, 168);">类 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">CompletableFuture</code> 中增加了几个新的方法(<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">completeAsync</code> ,<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">orTimeout</code> 等)</strong> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="color: rgb(71, 193, 168);">Nashorn 引擎的增强</strong> :Nashorn 从 Java8 开始引入的 JavaScript 引擎,Java9 对 Nashorn 做了些增强,实现了一些 ES6 的新特性 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="color: rgb(71, 193, 168);">I/O 流的新特性</strong> :增加了新的方法来读取和复制 InputStream 中包含的数据 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="color: rgb(71, 193, 168);">改进应用的安全性能</strong> :Java 9 新增了 4 个 SHA- 3 哈希算法,SHA3-224、SHA3-256、SHA3-384 和 S HA3-512 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> ...... </section></li> </ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;font-weight: bold;font-size: 22px;border-bottom: 2px solid rgb(89, 89, 89);margin-bottom: 30px;color: rgb(89, 89, 89);"><span style="display: none;"></span><span style="display: inline-block;border-bottom: 2px solid rgb(89, 89, 89);">Java10</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">发布于 2018 年 3 月 20 日,最知名的特性应该是 var 关键字(局部变量类型推断)的引入了,其他还有垃圾收集器改善、GC 改进、性能提升、线程管控等一批新特性</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>var 关键字<span style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="color: rgb(71, 193, 168);">介绍</strong> :提供了 var 关键字声明局部变量: <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">var list = new ArrayList<String>(); // ArrayList<String></code> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="color: rgb(71, 193, 168);">局限性</strong> :只能用于带有构造器的 <strong style="color: rgb(71, 193, 168);">局部变量</strong>和 for 循环中 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);"><em style="color: rgb(76, 156, 215);">Guide 哥:实际上 Lombok 早就体用了一个类似的关键字,使用它可以简化代码,但是可能会降低程序的易读性、可维护性。一般情况下,我个人都不太推荐使用。</em></p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>不可变集合<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);"><strong style="color: rgb(71, 193, 168);">list,set,map 提供了静态方法<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">copyOf()</code>返回入参集合的一个不可变拷贝(以下为 JDK 的源码)</strong></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_png/iaIdQfEric9TxbbtGeZK0rNKmkI1KRObltNn5JibT4zzzNayj7SpviaYNALwSkkM5hGIj774zPVCkbicYkvNeJXVs4Q/640?wx_fmt=png") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">static</span> <E> <span style="line-height: 26px;">List<E> <span style="color: #a6e22e;font-weight: bold;line-height: 26px;">copyOf</span><span style="line-height: 26px;">(Collection<? extends E> coll)</span> </span>{<br> <span style="color: #f92672;font-weight: bold;line-height: 26px;">return</span> ImmutableCollections.listCopy(coll);<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);"><strong style="color: rgb(71, 193, 168);"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">java.util.stream.Collectors</code>中新增了静态方法,用于将流中的元素收集为不可变的集合</strong></p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>Optional<span style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 新增了 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">orElseThrow()</code>方法来在没有值时抛出异常 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>并行全垃圾回收器 G1<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">从 Java9 开始 G1 就了默认的垃圾回收器,G1 是以一种低延时的垃圾回收器来设计的,旨在避免进行 Full GC,但是 Java9 的 G1 的 FullGC 依然是使用单线程去完成标记清除算法,这可能会导致垃圾回收期在无法回收内存的时候触发 Full GC。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">为了最大限度地减少 Full GC 造成的应用停顿的影响,从 Java10 开始,G1 的 FullGC 改为并行的标记清除算法,同时会使用与年轻代回收和混合回收相同的并行工作线程数量,从而减少了 Full GC 的发生,以带来更好的性能提升、更大的吞吐量。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>应用程序类数据共享<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">在 Java 5 中就已经引入了类数据共享机制 (Class Data Sharing,简称 CDS),允许将一组类预处理为共享归档文件,以便在运行时能够进行内存映射以减少 Java 程序的启动时间,当多个 Java 虚拟机(JVM)共享相同的归档文件时,还可以减少动态内存的占用量,同时减少多个虚拟机在同一个物理或虚拟的机器上运行时的资源占用</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">Java 10 在现有的 CDS 功能基础上再次拓展,以允许应用类放置在共享存档中。CDS 特性在原来的 bootstrap 类基础之上,扩展加入了应用类的 CDS (Application Class-Data Sharing) 支持。其原理为:在启动时记录加载类的过程,写入到文本文件中,再次启动时直接读取此启动文本并加载。设想如果应用环境没有大的变化,启动速度就会得到提升</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>其他特性<span style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);"><strong style="color: rgb(71, 193, 168);">线程-局部管控</strong>:Java 10 中线程管控引入 JVM 安全点的概念,将允许在不运行全局 JVM 安全点的情况下实现线程回调,由线程本身或者 JVM 线程来执行,同时保持线程处于阻塞状态,这种方式使得停止单个线程变成可能,而不是只能启用或停止所有线程</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);"><strong style="color: rgb(71, 193, 168);">备用存储装置上的堆分配</strong>:Java 10 中将使得 JVM 能够使用适用于不同类型的存储机制的堆,在可选内存设备上进行堆内存分配</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);"><strong style="color: rgb(71, 193, 168);">统一的垃圾回收接口</strong>:Java 10 中,hotspot/gc 代码实现方面,引入一个干净的 GC 接口,改进不同 GC 源代码的隔离性,多个 GC 之间共享的实现细节代码应该存在于辅助类中。统一垃圾回收接口的主要原因是:让垃圾回收器(GC)这部分代码更加整洁,便于新人上手开发,便于后续排查相关问题。</p> </section></li> </ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;font-weight: bold;font-size: 22px;border-bottom: 2px solid rgb(89, 89, 89);margin-bottom: 30px;color: rgb(89, 89, 89);"><span style="display: none;"></span><span style="display: inline-block;border-bottom: 2px solid rgb(89, 89, 89);">Java11</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">Java11 于 2018 年 9 月 25 日正式发布,这是很重要的一个版本!Java 11 和 2017 年 9 月份发布的 Java 9 以及 2018 年 3 月份发布的 Java 10 相比,其最大的区别就是:在长期支持(Long-Term-Support)方面,<strong style="color: rgb(71, 193, 168);">Oracle 表示会对 Java 11 提供大力支持,这一支持将会持续至 2026 年 9 月。这是据 Java 8 以后支持的首个长期版本。</strong></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.8188679245283019" src="/upload/2c2035fb295e717d5279de501eaa0bea.png" data-type="png" data-w="795" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>字符串加强<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">Java 11 增加了一系列的字符串处理方法,如以下所示。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);"><em style="color: rgb(76, 156, 215);">Guide 哥:说白点就是多了层封装,JDK 开发组的人没少看市面上常见的工具类框架啊!</em></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_png/iaIdQfEric9TxbbtGeZK0rNKmkI1KRObltNn5JibT4zzzNayj7SpviaYNALwSkkM5hGIj774zPVCkbicYkvNeJXVs4Q/640?wx_fmt=png") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;"><span style="color: #75715e;line-height: 26px;">//判断字符串是否为空</span><br><span style="color: #a6e22e;line-height: 26px;">" "</span>.isBlank();<span style="color: #75715e;line-height: 26px;">//true</span><br><span style="color: #75715e;line-height: 26px;">//去除字符串首尾空格</span><br><span style="color: #a6e22e;line-height: 26px;">" Java "</span>.strip();<span style="color: #75715e;line-height: 26px;">// "Java" </span><br><span style="color: #75715e;line-height: 26px;">//去除字符串首部空格</span><br><span style="color: #a6e22e;line-height: 26px;">" Java "</span>.stripLeading(); <span style="color: #75715e;line-height: 26px;">// "Java " </span><br><span style="color: #75715e;line-height: 26px;">//去除字符串尾部空格</span><br><span style="color: #a6e22e;line-height: 26px;">" Java "</span>.stripTrailing(); <span style="color: #75715e;line-height: 26px;">// " Java" </span><br><span style="color: #75715e;line-height: 26px;">//重复字符串多少次</span><br><span style="color: #a6e22e;line-height: 26px;">"Java"</span>.repeat(<span style="line-height: 26px;">3</span>); <span style="color: #75715e;line-height: 26px;">// "JavaJavaJava" </span><br><br><span style="color: #75715e;line-height: 26px;">//返回由行终止符分隔的字符串集合。</span><br><span style="color: #a6e22e;line-height: 26px;">"A\nB\nC"</span>.lines().count(); <span style="color: #75715e;line-height: 26px;">// 3 </span><br><span style="color: #a6e22e;line-height: 26px;">"A\nB\nC"</span>.lines().collect(Collectors.toList()); <br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>ZGC:可伸缩低延迟垃圾收集器<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);"><strong style="color: rgb(71, 193, 168);">ZGC 即 Z Garbage Collector</strong>,是一个可伸缩的、低延迟的垃圾收集器。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">ZGC 主要为了满足如下目标进行设计:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> GC 停顿时间不超过 10ms </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 即能处理几百 MB 的小堆,也能处理几个 TB 的大堆 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 应用吞吐能力不会下降超过 15%(与 G1 回收算法相比) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 方便在此基础上引入新的 GC 特性和利用 colord </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 针以及 Load barriers 优化奠定基础 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 当前只支持 Linux/x64 位平台 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">ZGC 目前 <strong style="color: rgb(71, 193, 168);">处在实验阶段</strong>,只支持 Linux/x64 平台</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>标准 HTTP Client 升级<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">Java 11 对 Java 9 中引入并在 Java 10 中进行了更新的 Http Client API 进行了标准化,在前两个版本中进行孵化的同时,Http Client 几乎被完全重写,并且现在完全支持异步非阻塞。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">并且,Java11 中,Http Client 的包名由 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">jdk.incubator.http</code> 改为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">java.net.http</code>,该 API 通过 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(198, 73, 128);">CompleteableFuture</code> 提供非阻塞请求和响应语义。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(89, 89, 89);">使用起来也很简单,如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_png/iaIdQfEric9TxbbtGeZK0rNKmkI1KRObltNn5JibT4zzzNayj7SpviaYNALwSkkM5hGIj774zPVCkbicYkvNeJXVs4Q/640?wx_fmt=png") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">var</span> request = HttpRequest.newBuilder() <br><br> .uri(URI.create(<span style="color: #a6e22e;line-height: 26px;">"https://javastack.cn"</span>)) <br><br> .GET() <br><br> .build(); <br><br><span style="color: #f92672;font-weight: bold;line-height: 26px;">var</span> client = HttpClient.newHttpClient(); <br><br><span style="color: #75715e;line-height: 26px;">// 同步 </span><br><br>HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); <br><br>System.out.println(response.body()); <br><br><span style="color: #75715e;line-height: 26px;">// 异步 </span><br><br>client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) <br><br> .thenApply(HttpResponse::body) <br><br> .thenAccept(System.out::println); <br><br><br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>简化启动单个源代码文件的方法<span style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 增强了 Java 启动器,使其能够运行单一文件的 Java 源代码。此功能允许使用 Java 解释器直接执行 Java 源代码。源代码在内存中编译,然后由解释器执行。唯一的约束在于所有相关的类必须定义在同一个 Java 文件中 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 对于 Java 初学者并希望尝试简单程序的人特别有用,并且能和 jshell 一起使用 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 一定能程度上增强了使用 Java 来写脚本程序的能力 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;color: rgb(89, 89, 89);"><span style="display: none;"></span>用于 Lambda 参数的局部变量语法<span style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 从 Java 10 开始,便引入了局部变量类型推断这一关键特性。类型推断允许使用关键字 var 作为局部变量的类型而不是实际类型,编译器根据分配给变量的值推断出
作者:微信小助手
<section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">在视频创作过程中,有时会遇到人像抠图的需求,最一般的做法是使用PR、AE等工具将视频中的每一帧图像手动抠图。这么繁琐的步骤在理工男面前简直是不可存在的,那么有什么简单的方法能快速抠图吗?当然有啦,接下来给大家介绍如何使用PaddleHub一键视频人像抠图。</span> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);text-align: center;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;display: inline-block;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;display: flex;justify-content: center;align-items: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;width: 1.3em;height: 1.3em;border-radius: 100%;background-image: -webkit-linear-gradient(top, rgb(41, 50, 225), rgb(41, 50, 225));overflow: hidden;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <section data-brushtype="text" style="padding: 4px 0.8em;max-width: 100%;letter-spacing: 1.5px;transform: rotate(0deg);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;font-stretch: normal;font-size: 12px;line-height: normal;font-family: Times;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(2, 30, 170);letter-spacing: 1px;font-size: 20px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 微软雅黑, "Microsoft YaHei";box-sizing: border-box !important;overflow-wrap: break-word !important;">效果展示</span></strong><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> </section> </section> </section> <section style="max-width: 100%;display: inline-block;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;display: flex;justify-content: center;align-items: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;width: 1.5em;height: 1.5em;border-radius: 100%;background-image: -webkit-linear-gradient(left, rgb(41, 50, 225), rgb(37, 250, 250));overflow: hidden;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <section style="margin-top: 10px;margin-left: -8px;max-width: 100%;width: 1em;height: 1em;border-radius: 100%;background-color: rgb(26, 44, 237);overflow: hidden;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> </section> </section> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <h1 style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">首先展示一些抠图完毕的小片段,上一秒我还在家里的小房间,下一秒我就出现在了土耳其。</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></h1> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.5625" data-type="gif" data-w="320" class="__bg_gif" src="/upload/538bd13ae496dc546bf5e5525cc4559.gif" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 320px !important;visibility: visible !important;"> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">那顺便去看看埃菲尔铁塔呗。</span> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.5625" data-type="gif" data-w="320" class="__bg_gif" src="/upload/a2756f7be21c76d57270929ea64889a6.gif" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 320px !important;visibility: visible !important;"> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">到洛杉矶的海边散散步。</span> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.5625" data-type="gif" data-w="320" class="__bg_gif" src="/upload/6889d1c59bd91ae94743a079bfcbb43f.gif" style="float: none;display: inline;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 320px !important;visibility: visible !important;"> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">到上海欢乐谷锻炼锻炼身体。</span> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.5625" data-type="gif" data-w="320" class="__bg_gif" src="/upload/a90ff1bec50a2a1bbdb669405150c1fc.gif" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 320px !important;visibility: visible !important;"> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">最后到东京的观景台上看个日落</span> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.5625" data-type="gif" data-w="320" class="__bg_gif" src="/upload/f04d6de87b5cc974ad880ae15400fe4e.gif" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 320px !important;visibility: visible !important;"> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">视频效果是不是很逼真呢,一天环游世界不是梦哈哈哈……</span> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">其实这些人像素材都是在房间里拍摄,然后使用PaddleHub工具库一键抠图,最后使用PR进行后期创作的,接下来介绍下如何操作吧。</span> </section> <h1 style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"></h1> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);text-align: center;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;display: inline-block;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;display: flex;justify-content: center;align-items: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;width: 1.3em;height: 1.3em;border-radius: 100%;background-image: -webkit-linear-gradient(top, rgb(41, 50, 225), rgb(41, 50, 225));overflow: hidden;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <section data-brushtype="text" style="padding: 4px 0.8em;max-width: 100%;letter-spacing: 1.5px;transform: rotate(0deg);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;font-stretch: normal;font-size: 12px;line-height: normal;font-family: Times;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(2, 30, 170);letter-spacing: 1px;font-size: 20px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 微软雅黑, "Microsoft YaHei";box-sizing: border-box !important;overflow-wrap: break-word !important;">这是如何实现的?</span></strong><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> </section> </section> </section> <section style="max-width: 100%;display: inline-block;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;display: flex;justify-content: center;align-items: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;width: 1.5em;height: 1.5em;border-radius: 100%;background-image: -webkit-linear-gradient(left, rgb(41, 50, 225), rgb(37, 250, 250));overflow: hidden;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <section style="margin-top: 10px;margin-left: -8px;max-width: 100%;width: 1em;height: 1em;border-radius: 100%;background-color: rgb(26, 44, 237);overflow: hidden;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> </section> </section> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">关注飞桨的小伙伴是否还记得前几天推过的<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=Mzg2OTEzODA5MA==&mid=2247491228&idx=1&sn=a7da5092bdf12312e89e790f6d12211e&chksm=cea0f559f9d77c4f94dfe5d23e6515f3b9dc1c40ebee22a3d1087dd394ff402229b5074c23c2&scene=21#wechat_redirect" textvalue="别再用PS了,我用5行Python代码就实现了批量抠图" data-itemshowtype="11" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">别再用PS了,我用5行Python代码就实现了批量抠图</a>,视频人像抠图也是类似的,只要把视频的每一帧图像所含有的人像提取出来,然后加上背景重新合成视频就可以啦。大体的步骤知道了,那接下来开始实践吧。</span> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">哦对了,还得有一段含有人像的素材,小伙伴们可以自己拍摄或者从网络搜集。</span> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section data-tools="135编辑器" data-id="86125" style="max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 1em;margin-right: 8px;margin-left: 8px;max-width: 100%;text-align: left;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="padding: 15px 2px;max-width: 100%;width: 3.5em;height: 2.5em;display: inline-block;text-align: center;line-height: 0.8em;color: rgb(254, 254, 254);background-color: rgb(26, 44, 237);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(255, 255, 255);font-size: 32px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">01</span> </section> </section> <section data-brushtype="text" style="margin-top: -3.1em;margin-left: 2.5em;padding: 15px 15px 15px 35px;max-width: 100%;min-height: 3.5em;border-width: 1px;border-style: solid;border-color: rgb(26, 44, 237);color: rgb(26, 44, 237);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;text-align: left;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(38, 38, 38);font-family: 微软雅黑, "Microsoft YaHei";font-weight: 700;letter-spacing: 2px;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">安装必要组建</span> </section> </section> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">需要安装的是飞桨框架和PaddleHub工具库,安装步骤可以参考<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=Mzg2OTEzODA5MA==&mid=2247491228&idx=1&sn=a7da5092bdf12312e89e790f6d12211e&chksm=cea0f559f9d77c4f94dfe5d23e6515f3b9dc1c40ebee22a3d1087dd394ff402229b5074c23c2&scene=21#wechat_redirect" textvalue="别再用PS了,我用5行Python代码就实现了批量抠图" data-itemshowtype="11" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">别再用PS了,我用5行Python代码就实现了批量抠图</a>。或者直接阅读原文进入飞桨官网查看安装步骤。</span> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <section data-tools="135编辑器" data-id="86125" style="max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 1em;margin-right: 8px;margin-left: 8px;max-width: 100%;text-align: left;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="padding: 15px 2px;max-width: 100%;width: 3.5em;height: 2.5em;display: inline-block;text-align: center;line-height: 0.8em;color: rgb(254, 254, 254);background-color: rgb(26, 44, 237);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(255, 255, 255);font-size: 32px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">02</span> </section> </section> <section data-brushtype="text" style="margin-top: -3.1em;margin-left: 2.5em;padding: 15px 15px 15px 35px;max-width: 100%;min-height: 3.5em;border-width: 1px;border-style: solid;border-color: rgb(26, 44, 237);color: rgb(26, 44, 237);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;text-align: left;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(38, 38, 38);font-family: 微软雅黑, "Microsoft YaHei";font-weight: 700;letter-spacing: 2px;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">人像抠图制作素材</span> </section> </section> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">由于目前PaddleHub人像抠图模型API的输入是单张图像的路径,故需要先将视频的每一帧图像分离存储后才能进行抠图。当然也可以通过修改模型的源码,将API的输入修改成图像输入,这样就省去了视频分离存储的步骤,具体的源码可以参考:</span> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;color: rgb(136, 136, 136);text-decoration: underline;box-sizing: border-box !important;overflow-wrap: break-word !important;">https://aistudio.baidu.com/aistudio/projectdetail/370260</span> <span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">,这里主要介绍前一种方法。</span> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <h4 style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(2, 30, 170);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">2.1 导入所有相关模块</span></strong></span></h4> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <section style="max-width: 100%;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <pre style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-right: 8px;margin-left: 8px;padding: 0.5em;max-width: 100%;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);line-height: 2em;box-sizing: border-box !important;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"> <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">import</span> cv2 <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">import</span> os <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">import</span> numpy <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">as</span> np <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">from</span> PIL <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">import</span> Image <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">import</span> paddlehub <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">as</span> hub <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section></pre> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <h4 style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;cursor: text;height: 10187px;color: rgb(2, 30, 170);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;cursor: text;height: 10187px;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">2.2 将视频内图像分离存储</span></strong></span></h4> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="max-width: 100%;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <pre style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-right: 8px;margin-left: 8px;padding: 0.5em;max-width: 100%;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);line-height: 2em;box-sizing: border-box !important;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"> def CutVideo2Image(video_path, img_path): <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> cap = cv2.VideoCapture(video_path) <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">index</span> = <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">0</span> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">while</span>(True): <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> ret,frame = cap.read() <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">if</span> ret: <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> cv2.imwrite(img_path + <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">'%d.jpg'</span> % <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">index</span>, frame) <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">index</span> += <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">1</span> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">else</span>: <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">break</span> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> cap.release() <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">print</span>( <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">'Video cut finish, all %d frame'</span> % <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">index</span>) <span style="max-width: 100%;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span> </section></pre> </section> <section style="max-width: 100%;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <blockquote style="padding: 15px 15px 15px 1rem;border-left-width: 6px;border-left-color: rgb(220, 230, 240);color: rgb(129, 145, 152);font-size: 0.9em;max-width: 100%;overflow-wrap: normal;line-height: inherit;background: rgb(242, 247, 251);overflow: auto;word-break: normal;box-sizing: border-box !important;"> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-size: inherit;color: inherit;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 该步骤将会把每一帧图像保存到本地目录。 </section> </blockquote> </section> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <h4 style="margin-right: 8px;margin-left: 8px;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;cursor: text;height: 10187p
作者:微信小助手
<section data-tools="135编辑器" data-id="90196" data-mpa-powered-by="yiban.io" style="max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 15px;color: rgb(62, 62, 62);line-height: 25.6px;widows: 1;font-family: 微软雅黑;border-width: 0px;border-style: none;border-color: initial;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin: 8px;padding: 10px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 25.6px;border-radius: 10px;height: auto;box-shadow: rgb(221, 221, 221) 2px 2px 8px;display: -webkit-flex;"> <section style="max-width: 100%;font-size: 16px;flex: 0 0 2cm;height: 78px;width: 75px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img data-copyright="0" data-cropselx1="0" data-cropselx2="76" data-cropsely1="0" data-cropsely2="76" data-ratio="1" data-type="jpeg" data-w="242" data-width="100%" title="undefined" src="/upload/a18d4e64e3d3e8c7a771cf5cd2eafc14.jpg" style="box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 76px !important;"></p> </section> <section style="padding-right: 10px;padding-left: 10px;max-width: 100%;flex: 1 1 auto;height: 55px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5Mjk2OTA0MA==&mid=2653854276&idx=1&sn=69ceef45b6e176400bbc3907223a43be&chksm=bd44027b8a338b6d3d33b1b8eddf709ea5217be9330970d29a83cbacf730fa4a84c5e58110f7&scene=21#wechat_redirect" textvalue="500强企业员工手册标准模板" data-itemshowtype="0" tab="innerlink" data-linktype="2"><span style="max-width: 100%;font-size: 14px;color: rgb(255, 104, 39);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">500强企业员工手册标准模板</strong></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></a> <section style="max-width: 100%;font-size: 13px;line-height: 20px;color: rgb(127, 127, 127);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5Mjk2OTA0MA==&mid=2653854276&idx=1&sn=69ceef45b6e176400bbc3907223a43be&chksm=bd44027b8a338b6d3d33b1b8eddf709ea5217be9330970d29a83cbacf730fa4a84c5e58110f7&scene=21#wechat_redirect" textvalue="500强企业员工手册标准模板" data-itemshowtype="0" tab="innerlink" data-linktype="2"><span style="max-width: 100%;color: rgb(165, 165, 165);font-size: 12px;box-sizing: border-box !important;overflow-wrap: break-word !important;">57家名企 & 11个行业&ppt</span><span style="max-width: 100%;color: rgb(165, 165, 165);font-size: 12px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></a> </section> </section> <section style="max-width: 100%;flex: 0 0 1.5cm;color: rgb(86, 187, 55);letter-spacing: 0px;text-align: center;line-height: 6;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 25px;max-width: 100px;vertical-align: middle;border-width: 1px;border-style: solid;border-color: rgb(86, 187, 55);border-radius: 5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;line-height: 2;letter-spacing: 0px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5Mjk2OTA0MA==&mid=2653854276&idx=1&sn=69ceef45b6e176400bbc3907223a43be&chksm=bd44027b8a338b6d3d33b1b8eddf709ea5217be9330970d29a83cbacf730fa4a84c5e58110f7&scene=21#wechat_redirect" textvalue="500强企业员工手册标准模板" data-itemshowtype="0" tab="innerlink" data-linktype="2"><span style="max-width: 100%;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);color: rgb(255, 76, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">领取</strong></span></a> </section> </section> </section> </section> </section> <section style="margin-right: 32px;margin-left: 32px;white-space: normal;max-width: 100%;letter-spacing: 0.544px;font-size: 16px;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);text-align: right;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="margin-right: 32px;margin-left: 32px;white-space: normal;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);font-size: 16px;text-align: center;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <section style="margin-right: 32px;margin-left: 32px;white-space: normal;max-width: 100%;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);font-size: 16px;text-align: left;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;text-align: justify;letter-spacing: 1px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">疫情期间要特别关注,2020年发工资的三个注意问题:</span> </section> <section style="margin-right: 32px;margin-left: 32px;white-space: normal;max-width: 100%;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);font-size: 16px;text-align: left;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;text-align: justify;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">1、低于最低工资标准的,违法;</span></strong></span> </section> <section style="margin-right: 32px;margin-left: 32px;white-space: normal;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: left;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;text-align: justify;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">2、不发工资条的,也属于违法行为;</span></strong></span> </section> <section style="margin-right: 32px;margin-left: 32px;white-space: normal;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: left;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;text-align: justify;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">3、各地发布的疫情期间工资发放标准,没按规定执行的,违法!</span></strong></span> </section> <section style="margin-right: 32px;margin-left: 32px;white-space: normal;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: left;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="margin-right: 32px;margin-left: 32px;white-space: normal;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);font-size: 16px;letter-spacing: 1px;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <p style="white-space: normal;text-align: center;"><img class="rich_pages" data-ratio="0.9602649006622517" data-s="300,640" src="/upload/ea5b94d7b07b9fc1e8b46b2be989a073.png" data-type="png" data-w="151" style="height: 84px;width: 87px;"></p> <section style="margin-right: 32px;margin-left: 32px;padding-right: 0em;padding-left: 0em;white-space: normal;max-width: 100%;letter-spacing: 0.544px;font-size: 16px;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);text-align: center;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 1px;color: rgb(255, 169, 0);font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">总工会办公厅发文明确</strong></span> </section> <section data-support="96编辑器" data-style-id="25388" style="white-space: normal;max-width: 100%;box-sizing: border-box;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);font-size: 16px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;overflow-wrap: break-word !important;"> <section style="max-width: 100%;min-height: 1em;line-height: 2em;letter-spacing: 2px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-right: 32px;margin-left: 32px;max-width: 100%;letter-spacing: 1px;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <section style="margin-right: 32px;margin-left: 32px;max-width: 100%;letter-spacing: 1px;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">之前,全国总工会发文,针对疫情中企业复工、工资计算、在家办公、劳动关系都做出了明确。<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span> </section> </section> </section> <section style="margin-right: 32px;margin-left: 32px;white-space: normal;max-width: 100%;box-sizing: border-box;font-size: 16px;background-color: rgb(255, 255, 255);letter-spacing: 2px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;line-height: 1.75em;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <section style="margin-bottom: 15px;white-space: normal;max-width: 100%;box-sizing: border-box;letter-spacing: 0.544px;font-size: 16px;background-color: rgb(255, 255, 255);text-align: center;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;overflow-wrap: break-word !important;"> <section style="max-width: 100%;min-height: 1em;line-height: 2em;letter-spacing: 2px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-right: 32px;margin-left: 32px;max-width: 100%;text-align: justify;letter-spacing: 1px;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img class="rich_pages" data-ratio="0.36750483558994196" data-s="300,640" data-type="png" data-w="1034" src="/upload/69363b2f97e65030aa0e826150c7c4d2.png" style="box-shadow: rgb(170, 170, 170) 0px 0px 14px 0px;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: auto !important;"> </section> </section> </section> <section style="margin-bottom: 15px;white-space: normal;max-width: 100%;letter-spacing: 0.544px;font-size: 16px;background-color: rgb(255, 255, 255);text-align: left;line-height: 1.75em;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;min-height: 1em;line-height: 2em;letter-spacing: 2px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-right: 32px;margin-left: 32px;max-width: 100%;text-align: justify;letter-spacing: 1px;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(63, 63, 63);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">划重点:</strong></span> </section> </section> </section> <section style="white-space: normal;max-width: 100%;letter-spacing: 0.544px;font-size: 16px;background-color: rgb(255, 255, 255);text-align: left;line-height: 1.75em;font-family: -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;min-height: 1em;line-height: 2em;letter-spacing: 2px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-right: 32px;margin-left: 32px;max-width: 100%;text-align: justify;letter-spacing: 1px;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">1、</span></strong></span> <span style="max-width: 100%;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">对继续在家延迟复工,但却用完各类假期的员工,且不能提供正常劳动的职工的工资;</span> </section> <section style="margin-right: 32px;margin-left: 32px;max-width: 100%;text-align: justify;letter-spacing: 1px;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">参照国家关于停工、停产期间工资支付相关规定支付工资、发放生活费。</span></strong></span> </section> </section> </section> <section style="margin-right: 32px;margin-left: 32px;white-space: normal;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <section style="white-space: normal;max-width: 100%;letter-spacing: 0.544px;font-size: 16px;background-color: rgb(255, 255, 255);text-align: left;line-height: 1.75em;font-family: -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;min-height: 1em;line-height: 2em;letter-spacing: 2px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-right: 32px;margin-left: 32px;max-width: 100%;text-align: justify;letter-spacing: 1px;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">2、</span></strong></span><span style="max-width: 100%;font-size: 15px;">履行依法隔离期、医疗期职工,企业应当承担工资支付义务,安排以灵活方式在家上班的职工,企业应与员工协商一致,如无特殊情况,</span><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">按照正常工作期间的工资收入支付工资。</span></strong></span> </section> </section> </section> <section style="margin-right: 32px;ma
作者:微信小助手
<section data-width="100%" data-opacity="1" data-rotate="0" style="margin-right: auto;margin-left: auto;white-space: normal;width: 574px;opacity: 1;transform: rotateZ(0deg);text-align: center;"> <br> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;line-height: 1.6;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;margin-top: -10px;font-size: 15px;letter-spacing: 0.05em;color: rgb(89, 89, 89);"> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">当多线程访问共享可变数据时,涉及到线程间同步的问题,并不是所有时候,都要用到共享数据,所以就需要线程封闭出场了。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">数据都被封闭在各自的线程之中,就不需要同步,这种通过将数据封闭在线程中而避免使用同步的技术称为<strong style="color: rgb(53, 179, 120);">线程封闭</strong>。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">本文主要介绍线程封闭中的其中一种体现:ThreadLocal,将会介绍什么是 ThreadLocal;从 ThreadLocal 源码角度分析,最后介绍 ThreadLocal 的应用场景。</p> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;"><span style="display: none;"></span>什么是 ThreadLocal?</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">ThreadLocal 是 Java 里一种特殊变量,它是一个线程级别变量,每个线程都有一个 ThreadLocal 就是每个线程都拥有了自己独立的一个变量,竞态条件被彻底消除了,在并发模式下是绝对安全的变量。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">可以通过 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">ThreadLocal<T> value = new ThreadLocal<T>();</code> 来使用。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">会自动在每一个线程上创建一个 T 的副本,副本之间彼此独立,互不影响,可以用 ThreadLocal 存储一些参数,以便在线程中多个方法中使用,用以代替方法传参的做法。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">下面通过例子来了解下 ThreadLocal:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_png/PkPSxQkjY4F5mNQg1lb9VeFk3ogjXbUqdsXBs8A6l4gXc1YruNia4MMlMWycvDNWRcM3aFp6Ol3PRYDd05o7N5Q/640?wx_fmt=png") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">public class ThreadLocalDemo {<br> /**<br> * ThreadLocal变量,每个线程都有一个副本,互不干扰<br> */<br> public static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>();<br><br> public static void main(String[] args) throws Exception {<br> new ThreadLocalDemo().threadLocalTest();<br> }<br><br> public void threadLocalTest() throws Exception {<br> // 主线程设置值<br> THREAD_LOCAL.set("wupx");<br> String v = THREAD_LOCAL.get();<br> System.out.println("Thread-0线程执行之前," + Thread.currentThread().getName() + "线程取到的值:" + v);<br><br> new Thread(new Runnable() {<br> @Override<br> public void run() {<br> String v = THREAD_LOCAL.get();<br> System.out.println(Thread.currentThread().getName() + "线程取到的值:" + v);<br> // 设置 threadLocal<br> THREAD_LOCAL.set("huxy");<br> v = THREAD_LOCAL.get();<br> System.out.println("重新设置之后," + Thread.currentThread().getName() + "线程取到的值为:" + v);<br> System.out.println(Thread.currentThread().getName() + "线程执行结束");<br> }<br> }).start();<br> // 等待所有线程执行结束<br> Thread.sleep(3000L);<br> v = THREAD_LOCAL.get();<br> System.out.println("Thread-0线程执行之后," + Thread.currentThread().getName() + "线程取到的值:" + v);<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">首先通过 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">static final</code> 定义了一个 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">THREAD_LOCAL</code> 变量,其中 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">static</code> 是为了确保全局只有一个保存 String 对象的 ThreadLocal 实例;<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">final</code> 确保 ThreadLocal 的实例不可更改,防止被意外改变,导致放入的值和取出来的不一致,另外还能防止 ThreadLocal 的内存泄漏。上面的例子是演示在不同的线程中获取它会得到不同的结果,运行结果如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_png/PkPSxQkjY4F5mNQg1lb9VeFk3ogjXbUqdsXBs8A6l4gXc1YruNia4MMlMWycvDNWRcM3aFp6Ol3PRYDd05o7N5Q/640?wx_fmt=png") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">Thread-0线程执行之前,main线程取到的值:wupx<br>Thread-0线程取到的值:null<br>重新设置之后Thread-0线程取到的值为:huxy<br>Thread-0线程执行结束<br>Thread-0线程执行之后,main线程取到的值:wupx<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">首先在 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">Thread-0</code> 线程执行之前,先给 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">THREAD_LOCAL</code> 设置为 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">wupx</code>,然后可以取到这个值,然后通过创建一个新的线程以后去取这个值,发现新线程取到的为 null,意外着这个变量在不同线程中取到的值是不同的,不同线程之间对于 ThreadLocal 会有对应的副本,接着在线程 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">Thread-0</code> 中执行对 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">THREAD_LOCAL</code> 的修改,将值改为 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">huxy</code>,可以发现线程 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">Thread-0</code> 获取的值变为了 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">huxy</code>,主线程依然会读取到属于它的副本数据 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">wupx</code>,这就是线程的封闭。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">看到这里,我相信大家一定会好奇 ThreadLocal 是如何做到多个线程对同一对象 set 操作,但是 get 获取的值还都是每个线程 set 的值呢,接下来就让我们进入源码解析环节:</p> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;"><span style="display: none;"></span>ThreadLocal 源码解析</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">首先看下 ThreadLocal 都有哪些重要属性:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_png/PkPSxQkjY4F5mNQg1lb9VeFk3ogjXbUqdsXBs8A6l4gXc1YruNia4MMlMWycvDNWRcM3aFp6Ol3PRYDd05o7N5Q/640?wx_fmt=png") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">// 当前 ThreadLocal 的 hashCode,由 nextHashCode() 计算而来,用于计算当前 ThreadLocal 在 ThreadLocalMap 中的索引位置<br>private final int threadLocalHashCode = nextHashCode();<br>// 哈希魔数,主要与斐波那契散列法以及黄金分割有关<br>private static final int HASH_INCREMENT = 0x61c88647;<br>// 返回计算出的下一个哈希值,其值为 i * HASH_INCREMENT,其中 i 代表调用次数<br>private static int nextHashCode() {<br> return nextHashCode.getAndAdd(HASH_INCREMENT);<br>}<br>// 保证了在一台机器中每个 ThreadLocal 的 threadLocalHashCode 是唯一的<br>private static AtomicInteger nextHashCode = new AtomicInteger();<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">其中的 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">HASH_INCREMENT</code> 也不是随便取的,它转化为十进制是 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">1640531527</code>,<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">2654435769</code> 转换成 int 类型就是 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">-1640531527</code>,<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">2654435769</code> 等于 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">(√5-1)/2</code> 乘以 2 的 32 次方。<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">(√5-1)/2</code> 就是黄金分割数,近似为 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">0.618</code>,也就是说 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">0x61c88647</code> 理解为一个黄金分割数乘以 2 的 32 次方,它可以保证 nextHashCode 生成的哈希值,均匀的分布在 2 的幂次方上,且小于 2 的 32 次方。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">下面是 javaspecialists 中一篇文章对它的介绍:</p> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin: 10px 5px;border-left-color: rgb(53, 179, 120);border-right: 0px solid rgb(53, 179, 120);color: rgb(97, 97, 97);quotes: none;background: rgb(251, 249, 253);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">This number represents the golden ratio (sqrt(5)-1) times two to the power of 31 ((sqrt(5)-1) * (2^31)). The result is then a golden number, either 2654435769 or -1640531527.</p> </blockquote> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">下面用例子来证明下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_png/PkPSxQkjY4F5mNQg1lb9VeFk3ogjXbUqdsXBs8A6l4gXc1YruNia4MMlMWycvDNWRcM3aFp6Ol3PRYDd05o7N5Q/640?wx_fmt=png") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">private static final int HASH_INCREMENT = 0x61c88647;<br><br>public static void main(String[] args) throws Exception {<br> int n = 5;<br> int max = 2 << (n - 1);<br> for (int i = 0; i < max; i++) {<br> System.out.print(i * HASH_INCREMENT & (max - 1));<br> System.out.print(" ");<br><br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">运行结果为:<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">0 7 14 21 28 3 10 17 24 31 6 13 20 27 2 9 16 23 30 5 12 19 26 1 8 15 22 29 4 11 18 25</code></p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">可以发现元素索引值完美的散列在数组当中,并没有出现冲突。</p> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(53, 179, 120);"><span style="display: none;"></span>ThreadLocalMap<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">除了上述属性外,还有一个重要的属性 ThreadLocalMap,ThreadLocalMap 是 ThreadLocal 的静态内部类,当一个线程有多个 ThreadLocal 时,需要一个容器来管理多个 ThreadLocal,ThreadLocalMap 的作用就是管理线程中多个 ThreadLocal,源码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_png/PkPSxQkjY4F5mNQg1lb9VeFk3ogjXbUqdsXBs8A6l4gXc1YruNia4MMlMWycvDNWRcM3aFp6Ol3PRYDd05o7N5Q/640?wx_fmt=png") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">static class ThreadLocalMap {<br> /**<br> * 键值对实体的存储结构<br> */<br> static class Entry extends WeakReference<ThreadLocal<?>> {<br> // 当前线程关联的 value,这个 value 并没有用弱引用追踪<br> Object value;<br><br> /**<br> * 构造键值对<br> *<br> * @param k k 作 key,作为 key 的 ThreadLocal 会被包装为一个弱引用<br> * @param v v 作 value<br> */<br> Entry(ThreadLocal<?> k, Object v) {<br> super(k);<br> value = v;<br> }<br> }<br><br> // 初始容量,必须为 2 的幂<br> private static final int INITIAL_CAPACITY = 16;<br><br> // 存储 ThreadLocal 的键值对实体数组,长度必须为 2 的幂<br> private Entry[] table;<br><br> // ThreadLocalMap 元素数量<br> private int size = 0;<br><br> // 扩容的阈值,默认是数组大小的三分之二<br> private int threshold;<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">从源码中看到 ThreadLocalMap 其实就是一个简单的 Map 结构,底层是数组,有初始化大小,也有扩容阈值大小,数组的元素是 Entry,<strong style="color: rgb(53, 179, 120);">Entry 的 key 就是 ThreadLocal 的引用,value 是 ThreadLocal 的值</strong>。ThreadLocalMap 解决 hash 冲突的方式采用的是<strong style="color: rgb(53, 179, 120);">线性探测法</strong>,如果发生冲突会继续寻找下一个空的位置。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">这样的就有可能会发生内存泄漏的问题,下面让我们进行分析:</p> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(53, 179, 120);"><span style="display: none;"></span>ThreadLocal 内存泄漏<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">ThreadLocal 在没有外部强引用时,发生 GC 时会被回收,那么 ThreadLocalMap 中保存的 key 值就变成了 null,而 Entry 又被 threadLocalMap 对象引用,threadLocalMap 对象又被 Thread 对象所引用,那么当 Thread 一直不终结的话,value 对象就会一直存在于内存中,也就导致了内存泄漏,直至 Thread 被销毁后,才会被回收。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">那么如何避免内存泄漏呢?</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">在使用完 ThreadLocal 变量后,需要我们手动 remove 掉,防止 ThreadLocalMap 中 Entry 一直保持对 value 的强引用,导致 value 不能被回收,其中 remove 源码如下所示:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_png/PkPSxQkjY4F5mNQg1lb9VeFk3ogjXbUqdsXBs8A6l4gXc1YruNia4MMlMWycvDNWRcM3aFp6Ol3PRYDd05o7N5Q/640?wx_fmt=png") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">/**<br> * 清理当前 ThreadLocal 对象关联的键值对<br> */<br>public void remove() {<br> // 返回当前线程持有的 map<br> ThreadLocalMap m = getMap(Thread.currentThread());<br> if (m != null) {<br> // 从 map 中清理当前 ThreadLocal 对象关联的键值对<br> m.remove(this);<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">remove 方法的时序图如下所示:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.8435754189944135" src="/upload/ecb77a0681f9bc48ac0da866672655f8.png" data-type="png" data-w="358" style="display: block;margin-right: auto;margin-left: auto;width: auto;"> </figure> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">remove 方法是先获取到当前线程的 ThreadLocalMap,并且调用了它的 remove 方法,从 map 中清理当前 ThreadLocal 对象关联的键值对,这样 value 就可以被 GC 回收了。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">那么 ThreadLocal 是如何实现线程隔离的呢?</p> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(53, 179, 120);"><span style="display: none;"></span>ThreadLocal 的 set 方法<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">我们先去看下 ThreadLocal 的 set 方法,源码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_png/PkPSxQkjY4F5mNQg1lb9VeFk3ogjXbUqdsXBs8A6l4gXc1YruNia4MMlMWycvDNWRcM3aFp6Ol3PRYDd05o7N5Q/640?wx_fmt=png") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">/**<br> * 为当前 ThreadLocal 对象关联 value 值<br> *<br> * @param value 要存储在此线程的线程副本的值<br> */<br>public void set(T value) {<br> // 返回当前ThreadLocal所在的线程<br> Thread t = Thread.currentThread();<br> // 返回当前线程持有的map<br> ThreadLocalMap map = getMap(t);<br> if (map != null) {<br> // 如果 ThreadLocalMap 不为空,则直接存储<ThreadLocal, T>键值对<br> map.set(this, value);<br> } else {<br> // 否则,需要为当前线程初始化 ThreadLocalMap,并存储键值对 <this, firstValue><br> createMap(t, value);<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">set 方法的作用是把我们想要存储的 value 给保存进去。set 方法的流程主要是:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 先获取到当前线程的引用 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 利用这个引用来获取到 ThreadLocalMap </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 如果 map 为空,则去创建一个 ThreadLocalMap </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 如果 map 不为空,就利用 ThreadLocalMap 的 set 方法将 value 添加到 map 中 </section></li> </ul> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">set 方法的时序图如下所示:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="1.0279329608938548" src="/upload/50e0beca0af74c4c3ee22cdb50430e44.png" data-type="png" data-w="358" style="display: block;margin-right: auto;margin-left: auto;width: auto;"> </figure> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">其中 map 就是我们上面讲到的 ThreadLocalMap,可以看到它是通过当前线程对象获取到的 ThreadLocalMap,接下来我们看 getMap方法的源代码:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_png/PkPSxQkjY4F5mNQg1lb9VeFk3ogjXbUqdsXBs8A6l4gXc1YruNia4MMlMWycvDNWRcM3aFp6Ol3PRYDd05o7N5Q/640?wx_fmt=png") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">/**<br> * 返回当前线程 thread 持有的 ThreadLocalMap<br> *<br> * @param t 当前线程<br> * @return ThreadLocalMap<br> */<br>ThreadLocalMap getMap(Thread t) {<br> return t.threadLocals;<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">getMap 方法的作用主要是获取当前线程内的 ThreadLocalMap 对象,原来这个 ThreadLocalMap 是线程的一个属性,下面让我们看看 Thread 中的相关代码:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_png/PkPSxQkjY4F5mNQg1lb9VeFk3ogjXbUqdsXBs8A6l4gXc1YruNia4MMlMWycvDNWRcM3aFp6Ol3PRYDd05o7N5Q/640?wx_fmt=png") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">/**<br> * ThreadLocal 的 ThreadLocalMap 是线程的一个属性,所以在多线程环境下 threadLocals 是线程安全的<br> */<br>ThreadLocal.ThreadLocalMap threadLocals = null;<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">可以看出每个线程都有 ThreadLocalMap 对象,被命名为 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">threadLocals</code>,默认为 null,所以每个线程的 ThreadLocals 都是隔离独享的。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">调用 ThreadLocalMap.set() 时,会把当前 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">threadLocal</code> 对象作为 key,想要保存的对象作为 value,存入 map。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">其中 ThreadLocalMap.set() 的源码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_png/PkPSxQkjY4F5mNQg1lb9VeFk3ogjXbUqdsXBs8A6l4gXc1YruNia4MMlMWycvDNWRcM3aFp6Ol3PRYDd05o7N5Q/640?wx_fmt=png") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">/**<br> * 在 map 中存储键值对<key, value><br> *<br> * @param key threadLocal<br> * @param value 要设置的 value 值<br> */<br>private void set(ThreadLocal<?> key, Object value) {<br> Entry[] tab = table;<br> int len = tab.length;<br> // 计算 key 在数组中的下标<br> int i = key.threadLocalHashCode & (len - 1);<br> // 遍历一段连续的元素,以查找匹配的 ThreadLocal 对象<br> for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {<br> // 获取该哈希值处的ThreadLocal对象<br> ThreadLocal<?> k = e.get();<br><br> // 键值ThreadLocal匹配,直接更改map中的value<br> if (k == key) {<br> e.value = value;<br> return;<br> }<br><br> // 若 key 是 null,说明 ThreadLocal 被清理了,直接替换掉<br> if (k == null) {<br> replaceStaleEntry(key, value, i);<br> return;<br> }<br> }<br><br> // 直到遇见了空槽也没找到匹配的ThreadLocal对象,那么在此空槽处安排ThreadLocal对象和缓存的value<br> tab[i] = new Entry(key, value);<br> int sz = ++size;<br> // 如果没有元素被清理,那么就要检查当前元素数量是否超过了容量阙值(数组大小的三分之二),以便决定是否扩容<br> if (!cleanSomeSlots(i, sz) && sz >= threshold) {<br> // 扩容的过程也是对所有的 key 重新哈希的过程<br> rehash();<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">相信到这里,大家应该对 Thread、ThreadLocal 以及 ThreadLocalMap 的关系有了进一步的理解,下图为三者之间的关系:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.5926680244399185" src="/upload/d77a0c3fa54696b07affeb7f1349ced8.png" data-type="png" data-w="982" style="display: block;margin-right: auto;margin-left: auto;width: auto;"> </figure> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(53, 179, 120);"><span style="display: none;"></span>ThreadLocal 的 get 方法<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">了解完 set 方法后,让我们看下 get 方法,源码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_png/PkPSxQkjY4F5mNQg1lb9VeFk3ogjXbUqdsXBs8A6l4gXc1YruNia4MMlMWycvDNWRcM3aFp6Ol3PRYDd05o7N5Q/640?wx_fmt=png") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">/**<br> * 返回当前 ThreadLocal 对象关联的值<br> *<br> * @return<br> */<br>public T get() {<br> // 返回当前 ThreadLocal 所在的线程<br> Thread t = Thread.currentThread();<br> // 从线程中拿到 ThreadLocalMap<br> ThreadLocalMap map = getMap(t);<br> if (map != null) {<br> // 从 map 中拿到 entry<br> ThreadLocalMap.Entry e = map.getEntry(this);<br> // 如果不为空,读取当前 ThreadLocal 中保存的值<br> if (e != null) {<br> @SuppressWarnings("unchecked")<br> T result = (T) e.value;<br> return result;<br> }<br> }<br> // 若 map 为空,则对当前线程的 ThreadLocal 进行初始化,最后返回当前的 ThreadLocal 对象关联的初值,即 value<br> return setInitialValue();<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">get 方法的主要流程为:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 先获取到当前线程的引用 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 获取当前线程内部的 ThreadLocalMap </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 如果 map 存在,则获取当前 ThreadLocal 对应的 value 值 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 如果 map 不存在或者找不到 value 值,则调用 setInitialValue() 进行初始化 </section></li> </ul> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">get 方法的时序图如下所示:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="1.8" src="/upload/48f07775a0ba3e87f2a25eaa73681973.png" data-type="png" data-w="370" style="display: block;margin-right: auto;margin-left: auto;width: auto;"> </figure> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">其中每个 Thread 的 ThreadLocalMap 以 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">threadLocal</code> 作为 key,保存自己线程的 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">value</code> 副本,也就是保存在每个线程中,并没有保存在 ThreadLocal 对象中。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">其中 ThreadLocalMap.getEntry() 方法的源码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_png/PkPSxQkjY4F5mNQg1lb9VeFk3ogjXbUqdsXBs8A6l4gXc1YruNia4MMlMWycvDNWRcM3aFp6Ol3PRYDd05o7N5Q/640?wx_fmt=png") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">/**<br> * 返回 key 关联的键值对实体<br> *<br> * @param key threadLocal<br> * @return<br> */<br>private Entry getEntry(ThreadLocal<?> key) {<br> int i = key.threadLocalHashCode & (table.length - 1);<br> Entry e = table[i];<br> // 若 e 不为空,并且 e 的 ThreadLocal 的内存地址和 key 相同,直接返回<br> if (e != null && e.get() == key) {<br> return e;<br> } else {<br> // 从 i 开始向后遍历找到键值对实体<br> return getEntryAfterMiss(key, i, e);<br> }<br>}<br></code></pre> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(53, 179, 120);"><span style="display: none;"></span>ThreadLocalMap 的 resize 方法<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">当 ThreadLocalMap 中的 ThreadLocal 的个数超过容量阈值时,ThreadLocalMap 就要开始扩容了,我们一起来看下 resize 的源代码:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_png/PkPSxQkjY4F5mNQg1lb9VeFk3ogjXbUqdsXBs8A6l4gXc1YruNia4MMlMWycvDNWRcM3aFp6Ol3PRYDd05o7N5Q/640?wx_fmt=png") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">/**<br> * 扩容,重新计算索引,标记垃圾值,方便 GC 回收<br> */<br>private void resize() {<br> Entry[] oldTab = table;<br> int oldLen = oldTab.length;<br> int newLen = oldLen * 2;<br> // 新建一个数组,按照2倍长度扩容<br> Entry[] newTab = new Entry[newLen];<br> int count = 0;<br><br> // 将旧数组的值拷贝到新数组上<br> for (int j = 0; j < oldLen; ++j) {<br> Entry e = oldTab[j];<br> if (e != null) {<br> ThreadLocal<?> k = e.get();<br> // 若有垃圾值,则标记清理该元素的引用,以便GC回收<br> if (k == null) {<br> e.value = null;<br> } else {<br> // 计算 ThreadLocal 在新数组中的位置<br> int h = k.threadLocalHashCode & (newLen - 1);<br> // 如果发生冲突,使用线性探测往后寻找合适的位置<br> while (newTab[h] != null) {<br> h = nextIndex(h, newLen);<br> }<br> newTab[h] = e;<br> count++;<br> }<br> }<br> }<br> // 设置新的扩容阈值,为数组长度的三分之二<br> setThreshold(newLen);<br> size = count;<br> table = newTab;<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">resize 方法主要是进行扩容,同时会将垃圾值标记方便 GC 回收,扩容后数组大小是原来数组的两倍。</p> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;"><span style="display: none;"></span>ThreadLocal 应用场景</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">ThreadLocal 的特性也导致了应用场景比较广泛,主要的应用场景如下:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 线程间数据隔离,各线程的 ThreadLocal 互不影响 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 方便同一个线程使用某一对象,避免不必要的参数传递 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 全链路追踪中的 traceId 或者流程引擎中上下文的传递一般采用 ThreadLocal </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> Spring 事务管理器采用了 ThreadLocal </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> Spring MVC 的 RequestContextHolder 的实现使用了 ThreadLocal </section></li> </ul> <h1 data-tool="mdnice编辑器" style="font-size: 24px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(53, 179, 120);"><span style="display: none;"></span>总结</h1> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">本文主要从源码的角度解析了 ThreadLocal,并分析了发生内存泄漏的原因,最后对它的应用场景进行了简单介绍。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">欢迎留言交流讨论,原创不易,觉得文章不错,请在看转发支持一下。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;text-align: center;"><br></p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;text-align: left;"><span style="text-align: left;letter-spacing: 0.05em;">更详细的源码解析可以点击链接查看:</span><span style="text-align: left;letter-spacing: 0.05em;">https://github.com/wupeixuan/JDKSourceCode1.8</span><span style="letter-spacing: 0.05em;text-align: left;"></span></p> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin: 10px 5px;border-left-color: rgb(53, 179, 120);border-right: 0px solid rgb(53, 179, 120);color: rgb(97, 97, 97);quotes: none;background: rgb(251, 249, 253);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">参考</p> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">《Java并发编程实战》</p> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">https://www.javaspecialists.eu/archive/Issue164.html</p> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">https://mp.weixin.qq.com/s/vURwBPgVuv4yGT1PeEHxZQ</p> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">Java并发编程学习宝典</p> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">面试官系统精讲Java源码及大厂真题</p> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">Java 并发面试 78 讲</p> </blockquote> </section> <p><br></p> <section data-role="outer" label="Powered by 135editor.com" style="white-space: normal;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-role="paragraph" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-role="outer" label="Powered by 135editor.com" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="line-height: 1.8;font-size: 14px;padding-right: 8px;padding-left: 8px;letter-spacing: 1.2px;box-sizing: border-box;"> <section style="transform: rotate(0deg);-webkit-transform: rotate(0deg);-moz-transform: rotate(0deg);-o-transform: rotate(0deg);box-sizing: border-box;" powered-by="xiumi.us"> <section style="align-items: center;display: flex;margin: 10px 0%;box-sizing: border-box;"> <section style="display: inline-block;vertical-align: bottom;width: auto;flex: 1 0 1px;letter-spacing: 0px;box-sizing: border-box;"> <section style="margin-top: 0.5em;margin-bottom: 0.5em;box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-top: 1px dashed rgb(62, 62, 62);box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> </section> </section> <section style="display: inline-block;vertical-align: bottom;width: auto;flex: 0 1 auto;box-shadow: rgb(0, 0, 0) 0px 0px 0px;line-height: 0;padding-right: 5px;padding-left: 5px;box-sizing: border-box;"> <section style="transform: rotateZ(45deg);-webkit-transform: rotateZ(45deg);-moz-transform: rotateZ(45deg);-o-transform: rotateZ(45deg);box-sizing: border-box;" powered-by="xiumi.us"> <section style="text-align: center;box-sizing: border-box;"> <section style="display: inline-block;width: 10px;height: 10px;vertical-align: top;overflow: hidden;background-color: rgb(255, 222, 23);border-width: 1px;border-radius: 0px;border-style: solid;border-color: rgb(62, 62, 62);box-shadow: rgb(255, 255, 255) 1px 1px 0px inset;line-height: 0;letter-spacing: 0px;box-sizing: border-box;"> <section style="text-align: justify;box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> </section> </section> </section> </section> <section style="display: inline-block;vertical-align: bottom;width: auto;flex: 1 0 1px;box-sizing: border-box;"> <section style="margin-top: 0.5em;margin-bottom: 0.5em;box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-top: 1px dashed rgb(62, 62, 62);box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width: 0px;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> </section> </section> </section> </section> </section> <p style="max-width: 100%;min-height: 1em;text-align: center;letter-spacing: 2px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="font-weight: bolder;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(255, 203, 58);font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></span></p> <p style="max-width: 100%;min-height: 1em;text-align: center;letter-spacing: 2px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="font-weight: bolder;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(255, 203, 58);font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">也许你还想看</span></span></p> <section data-from="xmt-recommend" data-tools="新媒体排版" style="margin: 16px;display: flex;justify-content: center;"> <a href="http://mp.weixin.qq.com/s?__biz=MzU3NTY3MTQzMg==&mid=2247485744&idx=1&sn=b7680127f7fa37c597773eb7aa4082cb&chksm=fd1ed4d7ca695dc1d475b9fae022ac34e821f271486d2376439c7056c37d6a4b2cea6f4de0c5&scene=21#wechat_redirect" target="_blank" style="padding: 8px;color: rgb(89, 89, 89);display: flex;box-sizing: border-box;border-radius: 4px;box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 12px 0px;width: 545.799px;background-color: rgb(255, 255, 255) !important;" data-linktype="2"> <section style="margin-right: 8px;height: 56px;white-space: normal;width: 465.851px;"> <span style="display: -webkit-box;height: 42px;overflow: hidden;-webkit-line-clamp: 2;-webkit-box-orient: vertical;font-size: 16px;line-height: 20px;">安卓应用市场常用热修复腾讯的Tinker,阿里的Andfix(总结,对比,接入)</span> <span style="display: block;height: 20px;transform: scale(0.8);transform-origin: left top;color: rgba(0, 0, 0, 0.45) !important;">2020-02-06</span> </section> <section style="overflow: hidden;width: 56px;height: 56px;border-radius: 4px;flex-shrink: 0;"> <span style="display: block;width: 56px;height: 56px;top: 27.9861px;right: 27.9861px;background-size: cover;background-position: 50% center;background-image: url("https://mmbiz.qpic.cn/mmbiz_jpg/qMicvibdvl7p3pHgpdkAhWJweMC0TzbzpquCjZjxngmYib6FNzEjrHKlC7DoITyrqsyFjLbHDTyhJTzNRkfbyLWhg/640?wx_fmt=jpeg");"></span> </section></a> </section> <section data-from="xmt-recommend" data-tools="新媒体排版" style="margin: 16px;display: flex;justify-content: center;"> <a href="http://mp.weixin.qq.com/s?__biz=MzU3NTY3MTQzMg==&mid=2247485705&idx=1&sn=b2afe632aaf63d982cc456f37a349a37&chksm=fd1ed4eeca695df82620bcdbd117d30b7436e6808d73f5d1424af946669ca1c831fb42d6dc13&scene=21#wechat_redirect" target="_blank" style="padding: 8px;color: rgb(89, 89, 89);display: flex;box-sizing: border-box;border-radius: 4px;box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 12px 0px;width: 545.799px;background-color: rgb(255, 255, 255) !important;" data-linktype="2"> <section style="margin-right: 8px;height: 56px;white-space: normal;width: 465.851px;"> <span style="display: -webkit-box;height: 42px;overflow: hidden;-webkit-line-clamp: 2;-webkit-box-orient: vertical;font-size: 16px;line-height: 20px;">ViewHolder的MVVM实现</span> <span style="display: block;height: 20px;transform: scale(0.8);transform-origin: left top;color: rgba(0, 0, 0, 0.45) !important;">2020-01-23</span> </section> <section style="overflow: hidden;width: 56px;height: 56px;border-radius: 4px;flex-shrink: 0;"> <span style="display: block;width: 56px;height: 56px;top: 27.9861px;right: 27.9861px;background-size: cover;background-position: 50% center;background-image: url("https://mmbiz.qpic.cn/mmbiz_jpg/qMicvibdvl7p3QXRL4dAhjLsuJNJia6U3R2g8wzbxzeP2NQoqYqUzIJVYicLiaicibKvibsoufND0dWuJtHib1YHXU2Wm3Q/640?wx_fmt=jpeg");"></span> </section></a> </section> <section data-from="xmt-recommend" data-tools="新媒体排版" style="margin: 16px;display: flex;justify-content: center;"> <a href="http://mp.weixin.qq.com/s?__biz=MzU3NTY3MTQzMg==&mid=2247485605&idx=1&sn=971deec29834d110b463a6f3058a3c61&chksm=fd1ed542ca695c543061e23875a875efc7cc4cf7228a0df2377b53e3a1dcbaa47672588dea5d&scene=21#wechat_redirect" target="_blank" style="padding: 8px;color: rgb(89, 89, 89);display: flex;box-sizing: border-box;border-radius: 4px;box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 12px 0px;width: 545.799px;background-color: rgb(255, 255, 255) !important;" data-linktype="2"> <section style="margin-right: 8px;height: 56px;white-space: normal;width: 465.851px;"> <span style="display: -webkit-box;height: 42px;overflow: hidden;-webkit-line-clamp: 2;-webkit-box-orient: vertical;font-size: 16px;line-height: 20px;">AndroidQ强制黑暗(ForceDark)模式实践</span> <span style="display: block;height: 20px;transform: scale(0.8);transform-origin: left top;color: rgba(0, 0, 0, 0.45) !important;">2020-01-02</span> </section> <section style="overflow: hidden;width: 56px;height: 56px;border-radius: 4px;flex-shrink: 0;"> <span style="display: block;width: 56px;height: 56px;top: 27.9861px;right: 27.9861px;background-size: cover;background-position: 50% center;background-image: url("https://mmbiz.qpic.cn/mmbiz_jpg/qMicvibdvl7p1bvfxQbOoSD9S8HkoGAMevy5SGSVLqpzjfQv92QHmpkl6vG9msRGCUagXVNPEKiaXAoicPsIAloUibQ/640?wx_fmt=jpeg");"></span> </section></a> </section> <section style="line-height: 1.8;font-size: 14px;padding-right: 8px;padding-left: 8px;letter-spacing: 1.2px;box-sizing: border-box;"> <section style="text-align: center;margin-right: 0%;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 95%;vertical-align: middle;border-style: dashed;border-width: 1px;border-radius: 3px;border-color: rgb(174, 163, 162);overflow: hidden;padding-top: 15px;padding-bottom: 15px;box-sizing: border-box;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: middle;width: 55%;box-sizing: border-box;"> <section style="margin-top: 1px;margin-right: 0%;margin-left: 0%;transform: translate3d(8px, 0px, 0px);box-sizing: border-box;" powered-by="xiumi.us"> <section style="text-align: justify;line-height: 1.2;box-sizing: border-box;"> <p style="margin-bottom: 10px;white-space: normal;box-sizing: border-box;">加入<strong style="box-sizing: border-box;">搜狐技术作者天团</strong></p> <p style="margin-bottom: 10px;white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">千元稿费等你来!</strong></p> <p style="white-space: normal;box-sizing: border-box;">戳这里!☛</p> </section> </section> </section> <section style="display: inline-block;vertical-align: middle;width: 30%;box-sizing: border-box;"> <section style="margin-top: 1px;margin-right: 0%;margin-left: 0%;transform: translate3d(10px, 0px, 0px);box-sizing: border-box;" powered-by="xiumi.us"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;width: 100%;border-width: 0px;height: auto;box-sizing: border-box;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzU3NTY3MTQzMg==&mid=2247485220&idx=2&sn=08e3d10a011ebaa3cb073f76533ab4ee&chksm=fd1edac3ca6953d5af55ecabaf52784729be9d87f2c7e2e59ab8c325864f30f92bc453e8be97&scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" data-itemshowtype="0" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 0px;right: auto;bottom: auto;"><img data-ratio="0.9655172" src="/upload/99f400a9f637f20f511ed81662ecba1.png" data-type="png" data-w="232" style="vertical-align: middle;width: 100%;box-sizing: border-box;border-radius: 8px;box-shadow: rgb(170, 170, 170) 0px 0px 14px 0px;margin: 0px;"></span></a> </section> </section> </section> </section> </section> </section> <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;width: 95%;box-sizing: border-box;"> <img data-ratio="0.496875" src="/upload/dd71cb3db3e9867051184f316150576f.gif" data-type="gif" data-w="640" style="vertical-align: middle;width: 100%;box-sizing: border-box;box-shadow: rgb(170, 170, 170) 0px 0px 14px 0px;border-radius: 8px;"> </section> </section> </section> <section data-role="outer" label="Powered by 135editor.com" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> </section> </section> </section>