Giter Club home page Giter Club logo

myrecord's Introduction

Hi there 👋

:name

A passionate Java developer

  • 🔭 I’m currently Focusing on JavaSpringBoot
  • 🌱 I’m currently learning Vue3、ELK、K8s
  • ⚡ Interested in full stack.

myrecord's People

Contributors

bfchengnuo avatar lxlxc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

myrecord's Issues

关于线程GC的一道题

刷题中刷到的:

以下哪项陈述是正确的?
A:垃圾回收线程的优先级很高,以保证不再使用的内存将被及时回收
B:垃圾收集允许程序开发者明确指定释放哪一个对象
C:垃圾回收机制保证了JAVA程序不会出现内存溢出
D:进入”Dead”状态的线程将被垃圾回收器回收
E:以上都不对

答案写的是 E。
ABC 有很明显的错误,就不多说了,可以参考这篇笔记:
Java基础复习三

那么关键点就在 D 了,答案说的很敷衍:

进入 DEAD 的线程,它还可以恢复,GC不会回收

那我就有疑问了,进入 DEAD 的线程怎么恢复?

Java对象的属性拷贝效率比较

这个真是一个使用率很高的功能,VO 和 PO 大多相似度很高,如果有很多的属性那一个个 set 么?
显然太累了,所以对属性拷贝欲罢不能,不过因为涉及到反射,所以效率嘛。。。。

常用的拷贝工具库

  1. SpringFramework 的 BeanUtils
  2. cglib 的 BeanCopier
  3. Apache BeanUtils 包的 PropertyUtils 类

PS:由于 Apache BeanUtils 的 copyProperties 方法实在是效率低的可怕,还有转换风险,这里随便看看就好,反正没人用。。。

分布式中保证数据一致性的方案整理

先列下大纲,不断补充,补充完毕整理为笔记。

更新:已整理到博客,飞机

前置知识

  • CAP 定理
  • 二阶段协议 & XA规范
  • JTA
  • 最终一致性
  • 三阶段提交协议
  • Paxos
  • nwr 模型

分布式锁

新开主题,参见 #22

分布式事务

  • MQ 实现

扩展

  • 数据库中如何保证事务原子性

关于网络相关的

长期计划,毕竟这一块内容超级多,如果往下挖,我是看不到底的。。。
推荐 《计算机网络:自顶向下的方法》
包括但不限于

  • Socks 协议
  • 防火墙
  • ip 地址欺骗
  • DNS 相关
  • 桥接
  • 网络地址转换(Network Address Translation,NAT)
  • 隧道协议
  • 端口转发与端口映射
  • ARP

模型之VO、 PO、DO、DTO、 BO、 QO、DAO、POJO

PO(Persistant Object) 持久对象

在 O/R 映射的时候出现的概念,如果没有 O/R 映射,就没有这个概念存在了。
通常对应数据模型 ( 数据库 ), 本身还有部分业务逻辑的处理。
可以看成是与数据库中的表相映射的 java 对象。最简单的 PO 就是对应数据库中某个表中的一条记录,多个记录可以用 PO 的集合。 PO 中应该不包含任何对数据库的操作。

DO(Domain Object)领域对象

就是从现实世界中抽象出来的有形或无形的业务实体
一般和数据中的表结构对应。

TO(Transfer Object) ,数据传输对象

应用程序不同 tie( 关系 ) 之间传输的对象

DTO(Data Transfer Object)数据传输对象

这个概念来源于 J2EE 的设计模式,原来的目的是为了 EJB 的分布式应用提供粗粒度的数据实体,以减少分布式调用的次数,从而提高分布式调用的性能和降低网络负载;
但在这里,我泛指用于展示层与服务层之间的数据传输对象

VO(View Object) 值对象

视图对象,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来。

BO(Business Object) 业务对象

从业务模型的角度看 , 见 UML 元件领域模型中的领域对象。封装业务逻辑的 java 对象 , 通过调用 DAO 方法 , 结合 PO,VO 进行业务操作。
主要作用是把业务逻辑封装为一个对象。这个对象可以包括一个或多个其它的对象。 比如一个简历,有教育经历、工作经历、社会关系等等。
我们可以把教育经历对应一个 PO ,工作经历对应一个 PO ,社会关系对应一个 PO 。 建立一个对应简历的 BO 对象处理简历,每个 BO 包含这些 PO 。 这样处理业务逻辑时,我们就可以针对 BO 去处理。

POJO(Plain Ordinary Java Object) 简单无规则 java 对象

纯的传统意义的 java 对象。就是说在一些 Object/Relation Mapping 工具中,能够做到维护数据库表记录的 PO 完全是一个符合 Java Bean 规范的纯 Java 对象,没有增加别的属性和方法。
即最基本的 JavaBean。

DAO(Data Access Object) 数据访问对象

是一个 Sun 的一个标准 j2ee 设计模式, 这个模式中有个接口就是 DAO ,它负责持久层的操作。为业务层提供接口。此对象用于访问数据库。通常和 PO 结合使用, DAO 中包含了各种数据库的操作方法。通过它的方法 , 结合 PO 对数据库进行相关的操作。夹在业务逻辑与数据库资源中间。配合 VO, 提供数据库的 CRUD 操作。

Java 中的 if...else 和 switch 比较?

当判断固定个数的值的时候,可以使用 if,也可以使用 switch。

但是建议使用 switch,效率相对较高。

关于 switch 的一些细节:

  1. break 是可以省略的,如果省略了就一直执行到遇到 break 为止;
  2. switch 后面的小括号中的变量不支持浮点数,1.7+ 后支持字符串,当然也支持枚举类型;
  3. default 可以写在 switch 结构中的任意位置;如果将 default 语句放在了第一行,则不管 expression
    与 case 中的 value 是否匹配,程序会从 default 开始执行直到第一个 break 出现。

当判断数据范围,获取判断运算结果 boolean 类型时,需要使用 if。

效率问题

为什么说 switch 的效率高?

if ..else 走逻辑判断时,每条 if 语句都独立需要加载,都要走一遍判断。也就是每次都会将这个变量读取到寄存器再进行比较,而实际上只需要读取一次就可以了,这就是耗时的机制问题了。
switch..case 根据一个值进行多路分支,只做一次计算(一次读取),然后将表达式的值与每个 case 的值比较,进而选择哪一个 case 语句块。

效率的差距可能会在 10 倍左右

switch 只能是在常量选择分支时比 if..else 效率高,但是 if..else 能应用于更多的场合,if..else 比较灵活。

在 c 中,教科书也是这么说的,switch...case... 执行效率高,属于典型的以空间换时间(内部会维护一个类似 map 的表,找到对应直接跳转)。也就是说,(套用算法的行话)以提高空间复杂度为代价降低了时间复杂度。

其他

同时,使用 if 的时候,应尽量避免使用 else if ,甚至是 else;通过对条件的优化(比如反转,然后用 return 结束)只保留 if,可读性也好。

如果想优化 if 还纠结设计模式的话,可以考虑抽象成策略。

另外,实际开发中,有谁会想到 if 比 switch 的效率低呢?? 23333

不同系统的换行问题

起因:

执行一个 node 的程序时,提示 env: node\r: no such file or directory

能猜到是换行符的问题,github 的一个老哥使用 vim 的 set ff=unix 给解决了,于是,来补充下相关知识。


首先,换行与回车是不一样的:

  • 换行符就是另起一行 --- '\n' 换行(newline)
  • 回车符就是回到一行的开头 --- '\r' 回车(return)

所以,我们使用的回车其实是『回车换行符』

  • Windows 系统里面,每行结尾是 回车+换行(CR+LF),即 \r\n
  • UNIX/Linux/MacX+ 系统里,每行结尾只有 换行 LF,即 \n
  • Mac 老系统里(X 以前),每行结尾是 回车 CR 即 \r

一个直接后果是,Unix/Mac 系统下的文件在 Windows 里打开的话,所有文字会变成一行;
而 Windows 里的文件在 Unix/Mac 下打开的话,在每行的结尾可能会多出一个 ^M 符号。
Linux 保存的文件在 windows 上用记事本看的话会出现黑点。

Pojo、JavaBean、EJB比较

概览

Java语言欠缺属性、事件、多重继承功能。所以,如果要在Java程序中实现一些面向对象编程的常见需求,只能手写大量胶水代码。
Java Bean 正是编写这套胶水代码的惯用模式或约定。这些约定包括 getXxx、setXxx、isXxx、addXxxListener、XxxEvent 等。

  • 在 java 1996 年发布,当年 12 月即发布了 java bean1.00-A,有什么用呢?通过统一的规范可以设置对象的值(get、set 方法),这是最初的 java bean;
  • 在实际企业开发中,需要实现事务,安全,分布式,javabean 就不好用了;sun 公司就开始往上面堆功能,这里 java bean 就复杂为 EJB;
  • EJB 功能强大,但是太重了!此时出现 DI (依赖注入),AOP(面向切面)技术,通过简单的 java bean 也能完成 EJB 的事情,这里的 java bean 简化为 POJO;
  • Spring诞生了.

拓展

  • PO(persistence object):用于持久化时(例如保存到数据库或者缓存);
  • VO(value object):用于前端展示使用(例如放置到 JSP 中解析或者给前端传递数据)
  • DTO(data transfer object):用于接口互相调用返回,数据传输(例如很多接口调用返回值或消息队列内容);

这里规范有一个小坑:
属性名 ICar 是合法的,但 iCar 是非法的。
有一个要求(属性前两个字母大小写必须一致)主要是 get 和 set 方法无法区分,上面两个属性 set 方法都是SetICar()

链接:https://www.zhihu.com/question/19773379/answer/18307751

Mysql执行FIND_IN_SET慢

示例 SQL:

SELECT cardName
FROM diyCard
WHERE FIND_IN_SET(id, ( SELECT group_concat(id) FROM card))

当然可以加索引,但这并不是问题的关键,根据 SQL 的执行顺序,where 中的子查询要被执行 N 次,但这是不必要的。

修改后:

SELECT cardname
FROM diycard, ( SELECT group_concat(id) id FROM card) temp
WHERE
FIND_IN_SET(id, temp.card)

(select group_concat(id) from card) 加到 from 后面,执行 sql 时直接组装数据源。还有这里的 group_concat(id) 让这个数据源只有一条记录,所以不会产生笛卡尔集

当然,优化不止这一种,多使用 explain 分析查询语句。

参考:https://www.cnblogs.com/Tinsv/p/8316833.html

判断DOM元素是否处于焦点

本次用到的是 input,所以就用它来当例子。

首先要知道自带的两个事件:

  • onBlur:当输入框失去焦点后
  • onFocus:当输入框获得焦点后

如果使用的是 JQ,可以尝试下这两个函数:focus()blur() 不过现在逐步用的比较少了,当前的项目也没用。

//  jq 获取焦点元素
var $focused = $(':focus');

// jq 判断是否处于焦点
var hasFocus = $('input').is(':focus');

// 原生 - 获取焦点元素
var focused = document.activeElement;

// 原生 - 判断元素是否处于焦点
elem === elem.ownerDocument.activeElement;

PS:如果使用 Vue,绑定的时候不要忘记 prevent 例如:@blur.prevent

序列化和持久化对比

序列化

把一个对象变成某种形式(通常是二进制)进行保存和(网络)传输。
一般来说,序列化是为了传输和存储;

持久化

持久化就是把对象保存下来,通常是通过数据库保存;
一般来说,持久化是为了存储。

区别

序列化重点在于序列,序列的格式不确定,序列化就是把某样东西由原来的形式转化成另外一种种形式,而持久化只是把对象从内存到磁盘的一个操作;

Spring本类方法互相调用事务无效如何解决?

这个问题原理不难理解,就是 AOP 代理时,如果本类方法调用是没有切人的。

也就是说,被调用的方法无论有没有事务,都失效。

最简单的方法当然是。。。。你不写在一个类里就好了。。。虽然基本是废话没啥用

架构、框架概念解释

简单理解:

架构

架构就是组件/模块之间的关系;
可简单理解为这个应用都有哪些模块,它们之间是怎么连接和交互的,能把这个描述出来就行了

框架

框架,即 framework。其实就是某种应用的半成品,就是一组组件,供你选用完成你自己的系统。
简单说就是使用别人搭好的舞台,你来做表演。
而且,框架一般是成熟的,不断升级的软件。

JavaEE 比较著名的框架有 Spring 全家桶、Mybatis、Struts2、Hibernate 等

Readme Info

计划是在这 Issues 下记录一些小 Tips 或者临时想到的东西,兴趣 + 与计算机搭边的。

这些东西大多很杂,还有科普性质的,为了方便管理使用自带的 Labels;

大部分内容都是比较少的,或者暂时没有整理完的东西,长度和质量如果达到了一定程度就决定转移到仓库内或者博客上。

暂时比较乱,凑活看。


计划把 Web 那边的 Issues 也转移过来,相关内容使用 Web Label,就别搞分散了。。。

分布式锁的几种实现方案

经过上一主题,感觉这部分内容也不少,单独拆分出来吧,应该会很有意思吧~

更新:已整理到博客,飞机

大纲:

  • 介绍
  • 基于缓存(Redis 为例)实现分布式锁
  • 基于数据库实现分布式锁
  • 基于Zookeeper实现分布式锁

可以了解一下 Etcd

缓存更新的套路(时机)?

大体思路,应该是:先更新数据,再清除缓存。

不可避免,在高并发下会使一些客户端拿到的还是旧数据,但是相比先清缓存来说,算是好的了。。。

试想,两个并发操作,一个是更新操作,另一个是查询操作,更新操作删除缓存后,查询操作没有命中缓存,先把老数据读出来后放到缓存中,然后更新操作更新了数据库。
于是,在缓存中的数据还是老的数据,导致缓存中的数据是脏的,而且还一直这样脏下去了。

更新缓存的的 Design Pattern 常见的有四种:

  1. Cache aside
  2. Read through
  3. Write through
  4. Write behind caching

最常用的应该是 Cache Aside Pattern
其具体逻辑如下:

  • 失效:
    应用程序先从 cache 取数据,没有得到,则从数据库中取数据,成功后,放到缓存中。
  • 命中:
    应用程序从 cache 中取数据,取到后返回。
  • 更新:
    先把数据存到数据库中,成功后,再让缓存失效。

更详细、完美的稍后再讨论。

WebDAV扫盲

基于 Web 的分布式编写和版本控制(WebDAV)是超文本传输协议(HTTP)的扩展,有利于用户间协同编辑和管理存储在万维网服务器文档。WebDAV 由互联网工程任务组的工作组在 RFC 4918 中定义。

WebDAV 协议为用户在服务器上创建,更改和移动文档提供了一个框架

一种基于 HTTP 协议的通信协议,它扩展了 HTTP 1.1,在 GET、POST、HEAD 等几个 HTTP 标准方法以外添加了一些新的方法,使应用程序可直接对 Web Server 直接读写,并支持写文件锁定 (Locking) 及解锁 (Unlock),还可以支持文件的版本控制。

通俗一点儿来说,WebDAV 就是一种互联网方法,应用此方法可以在服务器上划出一块存储空间,可以使用用户名和密码来控制访问,让用户可以直接存储、下载、编辑文件。

规定的 HTTP 请求:

  • Options、Head 和 Trace
    主要由应用程序用来发现和跟踪服务器支持和网络行为。

  • Get
    检索文档。

  • Put 和 Post
    将文档提交到服务器。

  • Delete
    销毁资源或集合。

  • Mkcol
    创建集合。

  • PropFind 和 PropPatch
    针对资源和集合检索和设置属性。

  • Copy 和 Move
    管理命名空间上下文中的集合和资源。

  • Lock 和 Unlock
    改写保护。


至于安全性,因为基于 HTTP,随着现在 HTTPS 的发展,以及 Web 鉴权的完善应该问题不大


还有就是 WebDAV 对开发的要求并不低,然后例如各大国内网盘,本来就免费,如果支持 WebDAV 那么基本都不需要专有客户端了,一个通用的支持 WebDAV 的客户端可以打通所有网盘了,就可以说厂商丧失了主导权

Windows实用命令整理

微软要发布 Windows Terminal 新命令行终端,之后命令也许会用的很爽吧。

  • SC - 服务管理
  • copy - 合并文件

运行:

  • mstsc - 远程桌面连接
  • calc - 计算器
  • notepad - 记事本
  • services.msc - 服务管理
  • gpedit.msc - 本地组策略编辑
  • winver - 查看 Windows 版本
  • regedit - 注册表编辑
  • shell:startup - 自定义开机启动项目
  • msconfig - 开机启动项配置

TimeUnit 工具类相关(JUC)

TimeUnit 是 JUC(java.util.concurrent)下面的一个类,表示给定单元粒度的时间段。

最常用的:

  • 用来时间单位的转换
  • 代替 Thread.sleep()
public class TimeUnitTest {
    public static void main(String[] args) {
        //convert 1 day to 24 hour
        System.out.println(TimeUnit.DAYS.toHours(1));
        //convert 1 hour to 60*60 second.
        System.out.println(TimeUnit.HOURS.toSeconds(1));
        //convert 3 days to 72 hours.
        System.out.println(TimeUnit.HOURS.convert(3, TimeUnit.DAYS));
    }
}

TimeUnit 提供了可读性更好的线程暂停操作,通常用来替换 Thread.sleep()

public class ThreadSleep {
    public static void main(String[] args) {
        new Thread(() -> {
            try {
                // Thread.sleep(500); //sleep 单位是毫秒
                TimeUnit.SECONDS.sleep(1); // 单位可以自定义,more convinent
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

CLI扫盲

当使用一些开发框架或者库的时候,有的会提供一个叫做 CLI 的工具,比如:
hexo-cli 、Vue-cli
这是我使用过的前端的几个工具,直接使用 NPM 安装。

命令行界面(英语:command-line interface,缩写:CLI)是在图形用户界面得到普及之前使用最为广泛的用户界面,它通常不支持鼠标,用户通过键盘输入指令,计算机接收到指令后,予以执行。
也有人称之为字符用户界面(character user interface, CUI)。

简单说就是提供的一个命令行方式的构建或者操作控制工具。

编程中所说的脚手架介绍

这里是 stackoverflow 上的一个回答:

Scaffolding is a meta-programming method of building database-backed software applications. It is a technique supported by some model-view-controller frameworks, in which the programmer may write a specification that describes how the application database may be used. The compiler uses this specification to generate code that the application can use to create, read, update and delete database entries, effectively treating the template as a "scaffold" on which to build a more powerful application.

翻译:

“脚手架”是一种元编程的方法,用于构建基于数据库的应用。许多MVC框架都有运用这种**。程序员编写一份specification(规格说明书),来描述怎样去使用数据库;而由(脚手架的)编译器来根据这份specification生成相应的代码,进行增、删、改、查数据库的操作。

我们把这种模式称为"脚手架",在脚手架上面去更高效的建造出强大的应用!


简单说就是帮你搭建好架子,脚手架工具会生成好一些基本代码,一般是遵循MVC结构代码。
比如,你知道 SSM、SSH 的脚手架么? o( ̄▽ ̄*)ゞ)) ̄▽ ̄*)o

CSS中z-index失效问题

z-index只对定位元素有效

并不是所有的定位设置都有效果;
absolute、relative 和 fixed 是肯定有效果的;

inherit 取决于父元素,如果父元素没有设置定位则 z-index 无效,注意低版本 IE 浏览器不支持这个值。

最后 static 这个静态定位,其实这是默认值,表示当前元素不进行定位,所以如果元素设置了这个属性值,其实是和没有设置是一样的,会使元素忽略掉 z-index 属性,使其不起作用。

父元素的层叠优先级比其他元素低

对于层叠元素的优先级对比都是在兄弟元素之间进行的,子元素的优先级并不会影响到父元素与其他兄弟元素之间的优先级关系。

也就是说,你子元素设置的 z-index 再大,父元素设置个 1 也终究会被(父元素同级)其他元素覆盖。

这里所指的层叠元素,是指有进行定位并且有设置 z-index 属性的元素。
如果没有进行定位和设置 z-index 的元素,其最终层叠优先级反而由当前元素的层叠子元素决定。
解放方法就是将父级层叠元素的z-index属性值设置大点。


当然如果你 z-index 设置的是一个非法值肯定也是无效的。
PS:z-index 是可以设置负值的
see: https://shiyousan.com/post/635861461562038949

深入 Java 中的编码问题

强烈推荐:https://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/index.html

为什么要编码

不知道大家有没有想过一个问题,那就是为什么要编码?我们能不能不编码?要回答这个问题必须要回到计算机是如何表示我们人类能够理解的符号的,这些符号也就是我们人类使用的语言。

由于人类的语言有太多,因而表示这些语言的符号太多,无法用计算机中一个基本的存储单元—— byte 来表示,因而必须要经过拆分或一些翻译工作,才能让计算机能理解。

我们可以把计算机能够理解的语言假定为英语,其它语言要能够在计算机中使用必须经过一次翻译,把它翻译成英语。这个翻译的过程就是编码。所以可以想象只要不是说英语的国家要能够使用计算机就必须要经过编码。这看起来有些霸道,但是这就是现状,这也和我们国家现在在大力推广汉语一样,希望其它国家都会说汉语,以后其它的语言都翻译成汉语,我们可以把计算机中存储信息的最小单位改成汉字,这样我们就不存在编码问题了。

所以总的来说,编码的原因可以总结为:

  1. 计算机中存储信息的最小单元是一个字节即 8 个 bit,所以能表示的字符范围是 0~255 个
  2. 人类要表示的符号太多,无法用一个字节来完全表示
  3. 要解决这个矛盾必须需要一个新的数据结构 char,从 char 到 byte 必须编码

如何“翻译”

明白了各种语言需要交流,经过翻译是必要的,那又如何来翻译呢?
计算中提拱了多种翻译方式,常见的有 ASCII、ISO-8859-1、GB2312、GBK、UTF-8、UTF-16 等。
它们都可以被看作为字典,它们规定了转化的规则,按照这个规则就可以让计算机正确的表示我们的字符。目前的编码格式很多,例如 GB2312、GBK、UTF-8、UTF-16 这几种格式都可以表示一个汉字,那我们到底选择哪种编码格式来存储汉字呢?这就要考虑到其它因素了,是存储空间重要还是编码的效率重要。根据这些因素来正确选择编码格式,下面简要介绍一下这几种编码格式。

ASCII 码

学过计算机的人都知道 ASCII 码,总共有 128 个,用一个字节的低 7 位表示,0~31 是控制字符如换行回车删除等;32~126 是打印字符,可以通过键盘输入并且能够显示出来。

ISO-8859-1

128 个字符显然是不够用的,于是 ISO 组织在 ASCII 码基础上又制定了一些列标准用来扩展 ASCII 编码,它们是 ISO-8859-1~ISO-8859-15,其中 ISO-8859-1 涵盖了大多数西欧语言字符,所有应用的最广泛。
ISO-8859-1 仍然是单字节编码,它总共能表示 256 个字符。

GB2312

它的全称是《信息交换用汉字编码字符集 基本集》,它是双字节编码,总的编码范围是 A1-F7,其中从 A1-A9 是符号区,总共包含 682 个符号,从 B0-F7 是汉字区,包含 6763 个汉字。

GBK

全称叫《汉字内码扩展规范》,是国家技术监督局为 windows95 所制定的新的汉字内码规范,它的出现是为了扩展 GB2312,加入更多的汉字,它的编码范围是 8140~FEFE(去掉 XX7F)总共有 23940 个码位,它能表示 21003 个汉字,它的编码是和 GB2312 兼容的,也就是说用 GB2312 编码的汉字可以用 GBK 来解码,并且不会有乱码。

GB18030

全称是《信息交换用汉字编码字符集》,是我国的强制标准,它可能是单字节、双字节或者四字节编码,它的编码与 GB2312 编码兼容,这个虽然是国家标准,但是实际应用系统中使用的并不广泛。

UTF-16

说到 UTF 必须要提到 Unicode(Universal Code 统一码),ISO 试图想创建一个全新的超语言字典,世界上所有的语言都可以通过这本字典来相互翻译。
可想而知这个字典是多么的复杂,关于 Unicode 的详细规范可以参考相应文档。Unicode 是 Java 和 XML 的基础,下面详细介绍 Unicode 在计算机中的存储形式。

UTF-16 具体定义了 Unicode 字符在计算机中存取方法。UTF-16 用两个字节来表示 Unicode 转化格式,这个是定长的表示方法,不论什么字符都可以用两个字节表示 (变长的,使用 2 或者 4 个字节进行编码,多数常用字是 2 字节),两个字节是 16 个 bit,所以叫 UTF-16。UTF-16 表示字符非常方便,每两个字节表示一个字符,这个在字符串操作时就大大简化了操作,这也是 Java 以 UTF-16 作为内存的字符存储格式的一个很重要的原因。

UTF-8

UTF-16 统一采用两个字节表示一个字符,虽然在表示上非常简单方便,但是也有其缺点,有很大一部分字符用一个字节就可以表示的现在要两个字节表示,存储空间放大了一倍,在现在的网络带宽还非常有限的今天,这样会增大网络传输的流量,而且也没必要。而 UTF-8 采用了一种变长技术,每个编码区域有不同的字码长度。
不同类型的字符可以是由 1~6 个字节组成
未证实:大多数常用字符使用 1-2 个字节就可以表示,少数会用 3 个(中文一般是 3 个),其他小众语言可能使用的字节数会多

UTF-8 有以下编码规则:

  1. 如果一个字节,最高位(第 8 位)为 0,表示这是一个 ASCII 字符(00 - 7F)。可见,所有 ASCII 编码已经是 UTF-8 了。
  2. 如果一个字节,以 11 开头,连续的 1 的个数暗示这个字符的字节数,例如:110xxxxx 代表它是双字节 UTF-8 字符的首字节。
  3. 如果一个字节,以 10 开始,表示它不是首字节,需要向前查找才能得到当前字符的首字节

MySQL中避免重复插入的方法

今天刚长见识了,听说了 MySQL 的 ignoreReplaceON DUPLICATE KEY UPDATE 语法

简单说,他们都是解决避免重复插入的问题。

这种场景非常常见,对于一条数据(有 id 信息),我们不知道它在数据库是否还存在,一般正常方案是先 select 查一下,如果没有就新增,如果有就更新。

这个操作可以一步完成。

关于权限修饰符的一道题

这题真是*操作,一个没留意。。

 public class HasStatic {// 1
    private static int x = 100;// 2
    public static void main(String args[]) {// 3
        HasStatic hsl = new HasStatic();// 4
        hsl.x++;// 5
        HasStatic hs2 = new HasStatic();// 6
        hs2.x++;// 7
        hsl = new HasStatic();// 8
        hsl.x++;// 9
        HasStatic.x--;// 10
        System.out.println(" x=" + x);// 11
    }
}

选项:

A: 程序通过编译,输出结果为:x=102
B: 程序通过编译,输出结果为:x=103
C: 10行不能通过编译.因为x星私有静态变量
D: 5行不能通过编译.因为引用了私有静态变量


答案是 A

我当时一看 private,直接肯定编译报错,选 D 啊,但是....

同一个类内,private 变量可以访问,所以CD错。

这是在同一个类中。。。。自己 new 的自己......

Netty中的NIO疑问?

首先,Java 中的几种 IO 模型之前已经说过;链接在这:同步异步并发并行

按照文章中的解释,Java 中的 IO 有:

  • BIO(Blocking I/O)
    同步阻塞 IO 模式
  • NIO(New I/O)
    包含有两种,同步非阻塞IO 和 异步阻塞IO
  • AIO( Asynchronous I/O)
    异步非阻塞 IO 模式,又叫做 NIO.2
    被称之为真 NIO,JDK7 开始支持

前置知识有了,就来看 Netty 了,我们都知道 Netty 是基于 NIO 的异步通讯,那么基本就可以确定说的是 Java 中的异步阻塞IO了;
那么,为什么 Netty 要使用 NIO,而不是 AIO?

在 Linux 系统上,AIO 的底层实现仍使用 EPOLL,与 NIO 相同,因此在性能上没有明显的优势;Windows 的 AIO 底层实现良好,但是 Netty 开发人员并没有把 Windows 作为主要使用平台考虑。

实际上,在 Netty 5.x 版本有过 AIO 的实现,但是发现性能还不如 NIO,就被废弃了。

而我们平时常说的 NIO 和 AIO 一般指的就是:
AIO 是真正的异步 IO,IO 吞吐量是要高于 NIO 的。两种 IO 模式的概念如下:

  • NIO:IO 复用模型,仍是阻塞 IO,通过复用 IO 线程提升吞吐量;
  • AIO:线程 A 执行 IO 操作时,注册回调函数,当 IO 操作执行完成后,内核通知应用层,由线程 B 执行回调逻辑;

再者,Netty 中所说的基于 NIO,指的是 NoneBlocking IO,非阻塞 IO;区别与 BIO,BIO 的全称是 Blocking IO,阻塞 IO。
之前也是介绍过,在这里:Netty学习笔记

NIO 并不是 Java 特有的概念,所以 Netty 中指的 NIO 也并不是 Java 中的 NIO

扫盲IaaS、PaaS、SaaS

这些缩写其实是云计算中的概念或者标准:

  • Infrastructure as a Service(IaaS)
    也就是所谓的基础设施级服务,比如阿里云,AWS 之类。

  • Platform as a Service(PaaS)
    也就是平台级服务,例如新浪云,你可以上传代码,它负责提供环境和运行,也是 K8S 的主要战场。

  • Software as a Service(SaaS)
    软件级别,很常见了,例如在线 Office

MySQL连接localhost与127.0.0.1区别

Whenever you specify "localhost" or "localhost:port" as server, the MySQL client library will override this and try to connect to a local socket (named pipe on Windows). If you want to use TCP/IP, use "127.0.0.1" instead of "localhost". If the MySQL client library tries to connect to the wrong local socket, you should set the correct path as in your PHP configuration and leave the server field blank.

localhost 使用的 Linux socket,127.0.0.1 使用的是 tcp/ip


Q:为什么我使用 localhost 一直没出问题?

A:因为你的本机中只有一个 mysql 进程, 如果你有一个 node1 运行在 3306, 有一个 node2 运行在 3307;
那么都会连接到同一个 mysql 进程, 因为 localhost 使用 Linux socket, 所以 -P 字段直接被忽略了

这是 linux 套接字网络的特性,win 平台不会有这个问题;
如果非要用,可以尝试在 my.cnf[mysql] 区段里添加 protocol=tcp

Git中的merge和rebase

虽然用 Git 的时间不短了,但是要么是自己一个人玩,要么就是非常简单的用,感觉根本没有用出真正的效率来,今天看到了有人在说 merge 和 rebase,脑袋中有点印象,按道理这俩应该用的是很频繁的才对。

借此机会做一下笔记,预感以后肯定会用到。

SpringBoot中的日期序列化转换

最常用的两个注解: @DateTimeFormat@JsonFormat

@DateTimeFormat 转换前端 String 类型到后端 Date 类型。

@JsonFormat 转换后端 Date 类型到前端 String 类型,如果只用到此注解,加到属性上或者方法上都可以;
如果跟 @DateTimeFormat 配合使用,此注解添加到 getter 方法上面,注意加 timezone="GMT+8"

示例:

class Main{
  @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
  private Date updateTime;

  // 一般配合 controller 使用
  public void test(@DateTimeFormat(pattern = "yyyy-MM-dd")Date date){}

  @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone="GMT+8")
  public Date getUpdateTime() {
    return updateTime;
  }

}

Ajax跨域中的预检请求

在项目中涉及到 Ajax 跨域时(使用 CORS 方式),注意到浏览器其实会发两次请求,一次类型为 OPTIONS,然后才是为们实际的 GET 或者 POST 请求。

并且,如果前面的 OPTIONS 请求没有成功,后面就不会再继续了,也就是,如果你的项目没有对 OPTIONS 请求进行处理,导致其失败的话,即使后面你加了类似 @crossorigin 的跨域处理,也是没有效果的。

在post请求中中文乱码的原因?(springMVC)

在前台,发送的数据已经使用 utf-8 正确编码,为什么传递到后台是乱码呢?

当然,解决方法有多个,最简单的直接用 spring 提供的过滤器就可以解决~

另外在 tomcat8.x 中,get 请求默认使用了 utf-8 所以再也不需要硬编码或者改 tomcat 的配置文件了~

下面回到开始的问题,猜测原因:
Servlet 3.0 规范中有关请求数据编码的解释如下:

当前很多浏览器并不发送带 Content-Type 头部的字符编码标识符,它会把字符编码的决定留在读取 HTTP 请求的时候。
如果客户端没有指明编码,容器用来创建请求读和解析 POST 数据的默认编码必须是 "ISO-8859-1"。
然而,为了提示开发者客户端没有成功发送一个字符编码,容器中 getCharacterEncoding 方法会返回 null。
如果客户端没有设置字符编码,并且请求数据使用了不同编码而不是上述的默认编码,程序将会出现中断。为了纠正这种状态,一个新的方法 setCharacterEncoding(String enc) 被添加到 ServletRequest 接口。
开发者调用这个方法能重写容器提供的字符编码。这个方法必须在解析 request 中任何 post 数据或者读任何输入之前调用。一旦数据已经被读取,调用这个方法不会影响它的编码。

拓展:深入分析web请求相应中的编码问题

数据库中的三范式

范式通俗讲就是:一张数据表的表结构所符合的某种设计标准的级别

推荐资料:https://www.zhihu.com/question/24696366

数据库范式也分为 1NF,2NF,3NF,BCNF,4NF,5NF。
一般在我们设计关系型数据库的时候,最多考虑到 BCNF 就够(一般都是到 3NF)。
符合高一级范式的设计,必定符合低一级范式,例如符合 2NF 的关系模式,必定符合 1NF。

第一范式(1NF)

强调的是列的原子性,即列不能够再分成其他几列;

符合 1NF 的关系中的每个属性都不可再分。

1NF 是所有关系型数据库的最基本要求,低于 1NF 建表都不会成功。

1NF 所带来的问题有 数据冗余过大、修改,插入,删除可能出现异常等

第二范式(2NF)

2NF 在 1NF 的基础之上,消除了非主属性对于码的部分函数依赖;
通俗讲,就是在 1NF 的前提下,另外包含两部分内容:
一是表必须有一个主键;
二是没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。

要有主键,并且要求其他字段都依赖于主键

关于什么是码?
设 K 为某表中的一个属性或属性组,若除 K 之外的所有属性都完全函数依赖于 K(这个“完全”不要漏了),那么我们称 K 为候选码,简称为码。在实际中我们通常可以理解为:假如当 K 确定的情况下,该表除 K 之外的所有属性的值也就随之确定,那么 K 就是码。

第三范式(3NF)

3NF 在 2NF 的基础之上,消除了非主属性对于码的传递函数依赖。
任何非主属性不依赖于其它非主属性【在2NF基础上消除传递依赖】

要消除传递依赖,方便理解,可以看做是“消除冗余”。

补充

关于 2NF 和 3NF,容易出现混淆:
2NF:非主键列是否完全依赖于主键,还是依赖于主键的一部分;
3NF:非主键列是直接依赖于主键,还是直接依赖于非主键列。

3NF 主要是要求不冗余,但是实际中也有情况为了提高查询效率进行适当的冗余,这可称为“反第三范式”

范式就是用来学习参考的,实际情况中可以适当进行变化修改。

CMS简介(扫盲)

CMS 是英语 Content Management System 的缩写,按英语的字面翻译就是内容管理系统,顾名思义,它主要是为了方便发布网络内容而存在的一体化 Web 管理系统。

内容管理系统的定义可以很狭窄,通常是指门户或商业网站的发布和管理系统;
定义也可以很宽泛,个人网站系统也可归入其中。
Wiki 也是一种内容管理系统,Blog 也算是一种内容管理系统。

文章发布是 CMS 的一个重要功能,但是一个功能较强大的 CMS 远不止如此,他们会有各种各样奇奇怪怪的功能模块,比如留言板,评论系统,预约系统,多语言模块等等。博客系统也是一种 CMS,只是它们更侧重于发布博客。

特点:

  • 有利于为数众多的人员投稿(或添砖加瓦)及分享所存储的数据;
  • 以类似于人力资源职位管理的方式,根据用户的角色控制他们对于以上数据的访问和使用的权限。
  • 有助于快捷简便地存储数据及检索到所需要的数据;
  • 资料的重复录入工作;
  • 降低工作报告写作的难度;
  • 加强用户间的交流;
  • 加强用户查证诊断他们组的角色;

常见的 CMS:
php类cms系统:dedecms、帝国cms、php168、phpcms、cmstop、discuz、phpwind 等
国外的著名cms系统:joomla、WordPress 、magento、drupal 、mambo。
比较新的有:ProcessWire,OctoberCMS,CraftCMS。
wiki 上的 CMS 系统列表参见:飞机

其中 Wordpress,Drupal,Joomla 是国外最流行的 3 大 CMS。
国内则是 DedeCMS 和帝国,PHPCMS 等。
国内的 CMS 会追求大而全,而国外的 CMS 更注重生态,更注重友好的接口,更多的功能留给第三方开发插件来实现。

关于常量池

所谓常量池,就是存储常量的地方,最常见的常量就是我们用 final 修饰的,和 static 一起用那么就是静态常量了。

常量池主要用于存放两大类常量:

  • 字面量 (Literal)
    字面量相当于 Java 语言层面常量的概念,如文本字符串,声明为 final 的常量值等
  • 符号引用量 (Symbolic References)
    符号引用则属于编译原理方面的概念,包括了如下三种类型的常量:类和接口的全限定名、字段名称和描述符、方法名称和描述符。

Java 中的常量池,还可以分为两种形态

  • 静态常量池
    所谓静态常量池,即 *.class 文件中的常量池,class 文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用 class 文件绝大部分空间。
  • 运行时常量池
    而运行时常量池,则是 jvm 虚拟机在完成类装载操作后,将 class 文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池,就是指方法区中的运行时常量池。

运行时常量池相对于 class 文件常量池的另外一个重要特征是具备动态性,Java 语言并不要求常量一定只有编译期才能产生,也就是并非预置入 class 文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用比较多的就是 String 类的 intern() 方法。


java 中基本类型的包装类的大部分都实现了常量池技术,这些类是:
Byte、Short、Integer、Long、Character、Boolean
另外两种浮点数类型的包装类则没有实现。
这5种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,但是超出此范围仍然会去创建新的对象。

线程的状态

java.lang.Thread.State:

  • NEW:
    线程已创建,尚未启动。
  • RUNNABLE:
    线程处于可运行状态,但是未必正在运行。
  • BLOCKED:
    被 Monitor 锁阻塞,表示当前线程在同步锁的场景运作。
    如果有大量线程是此状态,那么性能会比较差,不过不一定是发生了死锁。
  • WAITING:
    线程处于等待状态,由 Object.wait()Thread.join()LockSupport.park() 引起。
  • TIMED_WAITING:
    线程处于规定时间内的等待状态。
  • TERMINATED:
    线程执行结束。

高并发常问的 QPS、TPS

TPS

TPS:Transactions Per Second(每秒传输的事物处理个数)
即服务器每秒处理的事务数。

TPS 包括一条消息入和一条消息出,加上一次用户数据库访问。

TPS 是软件测试结果的测量单位。一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程。客户机在发送请求时开始计时,收到服务器响应后结束计时,以此来计算使用的时间和完成的事务个数。

一般的,评价系统性能均以每秒钟完成的技术交易的数量来衡量。系统整体处理能力取决于处理能力最低模块的 TPS 值。

QPS

每秒查询率 QPS 是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准,在因特网上,作为域名系统服务器的机器的性能经常用每秒查询率来衡量。

对应 fetches/sec,即每秒的响应请求数,也即是最大吞吐能力。

区别是什么呢?

引用个栗子:访问一个页面会请求服务器 3 次,一次访问产生一个 “T”,产生3个 “Q”。

  • QPS(TPS):每秒钟 request /事务 数量,在互联网领域,指每秒响应请求数(指 http 请求);QPS 不等于并发数。
  • 吞吐量:单位时间内处理的请求数量(通常由 QPS 与并发数决定);
  • 响应时间:系统对一个请求做出响应的平均时间。例如系统处理一个HTTP请求需要 200ms,这个 200ms 就是系统的响应时间

并发中关于各种锁的解释

看到有人列出的大纲:

  • 自旋锁
  • 自旋锁的其他种类
  • 阻塞锁
  • 可重入锁
  • 互斥锁
  • 悲观锁
  • 乐观锁
  • 公平锁
  • 非公平锁
  • 偏向锁
  • 对象锁
  • 线程锁
  • 锁粗化
  • 轻量级锁
  • 重量级锁
  • 锁消除
  • 锁膨胀
  • 信号量
  • 读写锁
  • 排它锁(X 锁)
  • 共享锁(S 锁)
  • 意向锁

大部分不了解,有部分名字很熟悉,完善各种锁的基本解释

对于OpenJDK应该所了解的

作为一个 Java 开发者,还是要有这个觉悟的,之前了解过但是没做笔记,看过一篇很好的文章,但是现在找不到了。。。

于是,这次我要记下来。

AOP、ASM、AspectJ、CGLIB之间的联系

先简单写写,大概可能也就这样了,这些概念不打算再深入。

AOP:面向切面,这个基本已经很了解了,博客里很早之前也写了,学 Spring 的时候这个肯定都搞过。

ASM:简单来说它是一个非常厉害的修改字节码的工具,注意是字节码也就是编译后的那个文件,修改后可以直接 load 到 JVM 运行,所以你可以在不修改代码、不重新编译的情况下来修改执行逻辑。

AspectJ:Eclipse 下的非常有名的一个为 Java 编程语言创建的面向切面的编程扩展,易用性强,定义了一系列的 AOP 名词,这些被 Spring 采用了,提供了类似的注解;只不过 AspectJ 本身是静态代理,也就是编译时织入的,跟 Spring 的动态方式不太一样。

CGLIB:这个也比较熟悉了,为了解决 JDK 动态代理不支持非接口的问题,使用动态修改字节码使用继承来解决非接口的 AOP 问题,内部使用的也是 ASM。

MD5与SHA

MD5 和 SHA-1 是目前使用比较广泛的散列 (Hash) 函数,也是在消息认证和数字签名中普遍使用的两种加密算法。

「MD5 消息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个 128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5 由罗纳德·李维斯特设计,于1992年公开,用以替换 MD4 算法。这套算法的程序在 RFC 1321 中被加以规范。」

「安全散列算法(英语:Secure Hash Algorithm,缩写为 SHA )是一个密码散列函数家族,是 FIPS 所认证的五种安全散列算法。能计算出一个数字消息所对应到的,长度固定的字符串(又称消息摘要)的算法。且若输入的消息不同,它们对应到不同字符串的概率很高。」

由于 MD5 与 SHA-1 均是从 MD4 发展而来,它们的结构和强度等特性有很多相似之处,SHA-1 与 MD5 的最大区别在于其摘要比 MD5 摘要长 32bit。

对于强行攻击,产生任何一个报文使之摘要等于给定报文摘要的难度:MD5 是 2128 数量级的操作,SHA-1 是 2160 数量级的操作。

产生具有相同摘要的两个报文的难度:MD5 是 264 是数量级的操作,SHA-1 是280 数量级的操作。

因而,SHA-1 对强行攻击的强度更大。但由于 SHA-1 的循环步骤比 MD5 多(80:64)且要处理的缓存大(160 比特:128 比特),SHA-1 的运行速度比 MD5 慢。

SHA-2:2001年发布,包括SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256。虽然至今尚未出现对 SHA-2 有效的攻击,它的算法跟 SHA-1 基本上仍然相似;因此有些人开始发展其他替代的散列算法。

关于getClass方法的一道题

题目:求输出结果

package test;
import java.util.Date; 
public class SuperTest extends Date{ 
    private static final long serialVersionUID = 1L; 
    private void test(){ 
       System.out.println(super.getClass().getName()); 
    } 
      
    public static void main(String[]args){ 
       new SuperTest().test(); 
    } 
}

有四个选项:
A:SuperTest
B:SuperTest.class
C:test.SuperTest
D:test.SuperTest.class

答案为 C


解析:

TestSuper 和 Date 的 getClass 都没有重写,他们都是调用 Object 的 getClass,而 Object 的 getClass 作用是返回的是运行时的类。
这个运行时的类就是当前类,所以
super.getClass().getName() 返回的是 test.SuperTest(包名 + 类名),与 Date 类无关。
要返回 Date 类的名字需要写 super.getClass().getSuperclass()

原来这个方法还可以这么玩。。。o( ̄▽ ̄*)ゞ)) ̄▽ ̄*)o

线程中的中断(interrupt)

一个线程在未正常结束之前,被强制终止是很危险的事情,因为它可能带来完全预料不到的严重后果;

比如会带着自己所持有的锁而永远的休眠,迟迟不归还锁等。

所以你看到 Thread.suspend()Thread.stop() 等方法都被标记为 Deprecated 了。

那么不能直接把一个线程弄死, 但有时候又有必要让一个线程死掉,或者让它结束某种等待的状态 该怎么办呢?

一个比较优雅而安全的做法是:使用等待/通知机制或者给那个线程一个中断信号, 让它自己决定该怎么办。

中断线程的使用场景:

在某个子线程中为了等待一些特定条件的到来,你调用了 Thread.sleep(10000),预期线程睡 10 秒之后自己醒来,但是如果这个特定条件提前到来的话,来通知一个处于 Sleep 的线程。

又比如说,线程通过调用子线程的 join 方法阻塞自己以等待子线程结束,但是子线程运行过程中发现自己没办法在短时间内结束,于是它需要想办法告诉主线程别等我了,这些情况下就需要中断.

中断是通过调用 Thread.interrupt() 方法来做的; 这个方法通过修改了被调用线程的中断状态来告知线程说它被中断了。

对于非阻塞中的线程,只是改变了中断状态;即 Thread.isInterrupted() 将返回 true;

对于可取消的阻塞状态中的线程,比如等待在这些函数上的线程:
Thread.sleep()Object.wait()Thread.join() 线程收到中断信号后会抛出 InterruptedException,同时会把中断状态置回为 true,但调用 Thread.interrupted() 会对中断状态进行复位。

// Interrupted 的经典使用代码
public void run(){
    try{
        // ....
        while(!Thread.currentThread().isInterrupted() && more work to do){
            // do more work;
        }
    } catch(InterruptedException e){
        // thread was interrupted during sleep or wait
    } finally{
        // cleanup, if required
    }
}

不是所有的阻塞方法收到中断后都可以取消阻塞状态,输入和输出流类会阻塞等待 I/O 完成,但是它们不抛出 InterruptedException,而且在被中断的情况下也不会退出阻塞状态.
尝试获取一个内部锁的操作(进入一个 synchronized 块)是不能被中断的,但是 ReentrantLock 支持可中断的获取模式即 tryLock(long time, TimeUnit unit)

https://blog.csdn.net/canot/article/details/51087772

数据库优化相关

虽然比较讨厌数据库相关的东西,但还是得学鸭~

缓慢更新,随缘更新。

我只是想记录下面两点:

  • 读库水平拆,横向扩展
  • 写库垂直拆,不同功能不同库

HashMap 的实现,以及是如何解决哈希冲突的

相关资料:
解决哈希冲突常用的两种方法是:开放定址法和链地址法

  • 开放定址法:
    当冲突发生时,使用某种探查(亦称探测)技术在散列表中形成一个探查(测)序列。沿此序列逐个单元地查找,直到找到给定 的关键字,或者碰到一个开放的地址(即该地址单元为空)为止(若要插入,在探查到开放的地址,则可将待插入的新结点存人该地址单元)。查找时探查到开放的 地址则表明表中无待查的关键字,即查找失败。
  • 链地址法:
    将所有关键字为同义词的结点链接在同一个单链表中。若选定的散列表长度为m,则可将散列表定义为一个由m个头指针组成的指针数 组T[0..m-1]。凡是散列地址为i的结点,均插入到以T[i]为头指针的单链表中。T中各分量的初值均应为空指针。

常见的哈希冲突解决方法:

  1. 开放地址法
  2. 链地址法(拉链法)
  3. 再散列
  4. 建立一个公共溢出区

  • 在 JDK1.6,JDK1.7 中,HashMap 采用位桶 + 链表实现,即使用链表处理冲突;
  • 在 JDK1.8 中,HashMap采用位桶(数组)+ 链表 + 红黑树实现;
    当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间,但是也是使用链地址法。

步骤:

  1. 当前索引数组为空,则将键值对以链表形式插入。
  2. 当前索引数组已经存在,则判断当前链表是红黑树还是链表,然后插入。
    如果是链表插入到最后一个,判断长度是否大于 8,大于 8 将链表转成红黑树。

但是在 java.util.HashMap 中,总体来说是使用的链地址法来解决冲突的
当然了,使用链地址法会导致 get 的效率从 o(1) 降至 o(n),所以在 Java8 中,使用的是平衡树来解决提高效率的

不是很明白,待补充

Tomcat中各个端口的作用?

从 tomcat 的配置文件中可以看到默认开了三个端口,分别是:8080(8443)、8009、8005。

8080(8443)端口

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
这应该是我们最熟悉的一个,平常开发测试也经常用,该 Connector 用于监听浏览器发送的请求. 设置成80 后可以直接使用 http://localhost 访问。
http 协议,其中 redirectPort 表示如果发送的是 https 请求,就将请求转发到 8443 端口。


8443 是默认的 https 监听端口。
默认未开启,如果要开启由于 tomcat 不自带证书所以除了取消注释之外,还要自己生成证书并在 中指定。

8005端口

<Server port="8005" shutdown="SHUTDOWN">
tomcat 监听的关闭端口,就是说 这个端口负责监听关闭 Tomcat 的请求
当执行 shutdown.sh 关闭 tomcat 时就是连接 8005 端口执行 “SHUTDOWN” 命令;
由此,我们直接用 telnet 向 8005 端口执行 “SHUTDOWN”(要大写,小写没用)来关闭 tomcat,这也是正统的关闭方式,如果这个端口没被监听,那么 sh 脚本就无效了。

8009端口

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/>
Nginx、Apache 等反向代理 tomcat 时就可以使用使用 ajp 协议反向代理到该端口。
虽然我们经常都是使用 http 反向代理到 8080 端口,但由于 ajp 建立 tcp 连接后一般长时间保持,从而减少了 http 反复进行 tcp 连接和断开的开销,所以反向代理中 ajp 是比 http 高效的。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.