导图社区 web开发中的知识点
web前端开发课程知识总结!内容包含javaweb,基础知识,数据结构和算法,开发中的安全规范,数据库与jdbc等等。是以时间为线索进行知识点的总计记录,包含数据库、变量、常量、数据类型、函数等基础知识。适合前端小白学习!
编辑于2021-05-25 17:07:30数据库与JDBC
MySQL
数据库操作
数据库的登录

修改数据库密码
方法一:修改mysql库中user表中的信息

方法二:在Linux命令行环境中执行,使用mysqladmin工具来设置密码

查看数据库结构
查看当前服务器中所有的数据库

查看当前使用的数据库中所包含的表

查看表的结构

创建和删除库和表
创建数据库

创建新的表

删除一个表

删除一个库

管理表中的数据记录
插入数据

删除数据
修改数据
查询数据
数据库的用户授权
授予权限

查看权限

撤销权限

数据库的备份和恢复
备份数据库
导出指定数据库中的部分表

导出一个或多个完整的库

备份mysql服务器中所有的库

恢复数据库

mysql的索引
mysql底层用的是B+tree

mysql的存储引擎
MyISAM(非聚集索引)

InnoDB(聚集索引)

InnoDB存储引擎的锁的三种算法
Record lock:单个行记录上的锁
Gap lock:间隙锁,锁定一个范围,不包括记录本身
Next-key lock:record+gap锁定一个范围,包含记录本身
mysql中的锁机制
按粒度划分
行级锁
页级锁
表级锁
储存引擎对锁的支持
MyISAM
MyISAM采用表级锁(table-level locking)
InnoDB
InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁
数据语言的分类
数据查询语言DQL
查
基础的查询
SELECT * FROM tb_name
where子句
比较运算符
大于、小于、等于、不等于、大于等于、小于等于
SELECT * FROM tb_name WHERE user_id >10;
逻辑运算符
逻辑运算符是用来拼接其他条件的。用and或者or来连接两个条件,如果用or来连接的时候必须使用小括号
SELECT * FROM tb_name WHERE user_id > 10 AND sex = '男'
LIKE模糊查询
通配符
%(百分号)匹配零个或者多个任意字符
_(下划线)匹配一个任意字符
sql
SELECT * FROM tb_name WHERE username LIKE '张%';查找username开头是张的数据
SELECT * FROM tb_name WHERE username LIKE '%张%';查询username中含有张的数据
SELECT * FROM tb_name WHERE username LIKE '%张';查询username字段的数据以张结尾的
SELECT * FROM tb_name WHERE username LIKE '张_';查询username以张开头后边有一个字符的数据
IN字段指定多个值查询
IN (value1,value2,value3,....)
SELECT * FROM tb_name WHERE user_id IN (1,3,5,7,9,11);查询user_id是1,3,5,7,9,11的所有数据
BETWEEN AND 区间查询
field BETWEEN value1 AND value2
SELECT * FROM user WHERE user_id BETWEEN 2 AND 9;查询user表中user_id大于等于2小于等于9的所有值
GROUP BY 分组查询
配合函数
count(field)获取符合条件出现的非null值的次数
SUM(field)获取所有符合条件的数据的总和
AVG(field)或者平均值
SELECT sex,COUNT(*) count FROM class GROUP BY sex;获取class表中男生和女生的数量
ORDER BY 查询排序
查询顺序
ORDER BY field DESC;降序查询
ORDER BY field ASC;升序查询
SELECT * FROM tb_name ORDER BY id DESC; 查询tb_name表中所有数据,按id的降序来查找
LIMIT 查询结果截取
参数
LIMIT 后边可以跟两个参数,如果只写一个表示从零开始查询指定长度,如果两个参数就是从第一个参数开始查询查询长度是第二个参数的值,俩个参数必须是整形。
SELECT * FROM tb_name LIMIT 5;查询tb_name表中的所有数据,只要前边的5条数据
SELECT * FROM tb_name LIMIT 5,5;查询tb_name中所有的数据,返回的结果是从第五条开始截取五条数据
关联查询
外关联
左关联
SELECT * FORM tb_name1 LEFT JOIN tb_name2 ON tb_name1.t2_id = tb_name2.t2_id;用表一的t2_id和表二的t2_id来关联,查询所有的值。
FROM 之后的表是主表
中关联
SELECT * FORM tb_name1 JOIN tb_name2 ON tb_name1.t2_id = tb_name2.t2_id;用表一的t2_id和表二的t2_id来关联,查询所有的值。
中关联没有主表
右关联
SELECT * FORM tb_name1 RIGHT JOIN tb_name2 ON tb_name1.t2_id = tb_name2.t2_id;用表一的t2_id和表二的t2_id来关联,查询所有的值。
在ON后边的表是主表
内关联
内管理的关联条件是用where来说关联的,多张表之间用AND来拼接where条件
SELECT * FROM tb_name1,tb_name2,.... WHERE tb_name1.t2_id = tb_name2.t2_id AND ...
外关联的说明
主表关联副表,如果副表数据不够用NULL来补全,但是中关联的时候,如果不够了,左边的数据或者右边的数据不会显示。直接去掉
事务
关键词
BEGIN开启事务
ROLLBACK;事务回滚
COMMIT;事务提交
必备条件
表的引擎为InnoDB
数据操纵语言DML
增
添加单条
INSERT INTO tb_name(`field1`,`field2`,....)VALUES('value1','value2',.....);
添加多条
INSERT INTO tb_name(`field1`,`field2`,....)VALUES('value1','value2',.....),('value1','value2',.....),('value1','value2',.....),....;
删
sql
DELETE FROM tb_name WHERE ...
注意
删除时必须加where条件
改
sql
UPDATE tb_name SET field1 = value1,field2 = value2,..... WHERE ....
注意
修改时必须加where条件
数据定义语言DDL
创建表
SQL : CREATE TABLE tb_name (建表的字段、类型、长度、约束、默认、注释)
约束
非空
NOT NULL
非负
UNSIGNED
主键
PRIMARY KEY
自增
AUTO_INCREMENT
默认
DEFAULT
注释
COMMENT
常用类型
极小整形
TINYINT
非负最大值255
1个字节
小整形
SAMLLINT
非负最大值65535
2个字节
整形
INT
非负最大值4 294 967 295
4个字节
单精度
FLOAT
4个字节
定长字符串
CHAR
最大保存255个字节
如果值没有到给定长度用空格补充
变长字符串
VARCHAR
最大保存255个字节
用多大占多大
文本
TEXT
最大保存65535个字节
表字段索引
唯一索引
添加
创建索引
CREATE UNIQUE INDEX index_name ON tb_name (account);
表字段修改
ALTER TABLE tb_name ADD UNIQUE index_name(field_name);
删除
DROP INDEX Index_nae ON tb_name;
DROP INDEX 索引名称 ON 表名
普通索引
添加
表字段修改
ALTER TABLE tb_name ADD INDEX Index_Name(`account`)
ALTER TABLE 表名 ADD INDEX 索引名称(字段名称);
创建索引
CREATE INDEX Index_name ON tb_name(`account`);
CREATE INDEX 索引名称 ON 表名(字段名);
删除
DROP INDEX Index_nae ON tb_name;
DROP INDEX 索引名称 ON 表名
主键
添加
ALTER TABLE tb_name ADD PRIMARY KEY (field_name);
ALTER TABLE 表名 ADD PRIMARY KEY (字段名称)
删除
ALTER TABLE tb_name DROP PRIMARY KEY;
数据控制语言DCL
MySQL函数
1.数学函数
ABS()绝对值
PI() π值
RAND()返回0到1内的随机值,可以通过提供一个参数(种子)使RAND()随机数生成器生成一个指定的值。
ROUND(x,y)返回参数x的四舍五入的有y位小数的值
MOD(x,y) 返回x/y的模(余数)
2.聚合函数
AVG(col)返回指定列的平均值
COUNT(col)返回指定列中非NULL值的个数
SUM(col)返回指定列的所有值之和
3.字符串函数
UCASE(str)或UPPER(str) 返回将字符串str中所有字符转变为大写后的结果
TRIM(str)去除字符串首部和尾部的所有空格
RTRIM(str) 返回字符串str尾部的空格
LTRIM(str) 从字符串str中切掉开头的空格
LENGTH(s)返回字符串str中的字符数
ASCII(char)返回字符的ASCII码值
4.日期和时间函数
CURDATE()或CURRENT_DATE() 返回当前的日期
CURTIME()或CURRENT_TIME() 返回当前的时间
FROM_UNIXTIME(时间戳) 格式化传入的时间戳,转成日期格式
UNIX_TIMESTAMP()获取系统当前的时间戳
NOW()返回当前的时间的日期
5.加密函数
MD5() 计算字符串str的MD5校验和
PASSWORD(str) 返回字符串str的加密版本,这个加密过程是不可逆转的,和UNIX密码加密过程使用不同的算法。
SHA() 计算字符串str的安全散列算法(SHA)校验和
6.控制流程函数
7.格式化函数
8.类型转化函数
9.系统信息函数
DATABASE() 返回当前数据库名
USER()或SYSTEM_USER() 返回当前登陆用户名
VERSION() 返回MySQL服务器的版本
CONNECTION_ID() 返回当前客户的连接ID
BENCHMARK(count,expr) 将表达式expr重复运行count次
mysql的索引底层的数据结构是怎么样的?
MySQL用的是B+Tree
每一次数据的变更都需要重新去维护索引结构,会带来大量的IO开销
索引在创建的时候,就要考虑那些不经常变更的字段
mysql的性能优化
mysql中怎么分析慢查询的
数据库中查询的各种连接
外连接
左连接
右连接
内连接
内连接和外链接有什么区别
交叉连接
mysql中的索引

mysql的索引类型
主键索引
 它 是一种特殊的唯一索引,不允许有空值
唯一索引
 索引列的值必须唯一,但允许有空值
普通索引
 最基本的索引,没有任何限制
全文索引
 
组合索引
 为了更多的提高mysql效率可建立组合索引,遵循”最左前缀“原则
查看和删除索引的命令

mysql高级操作
存储过程
存储过程创建和调用
存储过程的创建

存储过程的调用

存储过程游标的使用
什么是游标
游标是保存查询结果的临时区域
触发器
数据库
数据库中的事务
什么是事务
事务就是一个对数据库操作的序列,是一个不可分割的工作单位,要不这个序列里面的操作全部执行,要不全部不执行
mysql中怎么查询事务的隔离级别
mysql中怎么设置事务的隔离级别
事务的特性(ACID)
原子性
持久性
一致性
隔离性
事务的隔离四个级别
读未提交
读已提交
可重复读
可串行化
事务隔离级别中的概念
脏读
幻读
不可重复读
什么是视图
存储的查询语句,当调用的时候,产生结果集,视图充当的是虚拟表的角色.
数据库连接池
为什么要使用数据库连接池
常见的数据库连接池
C3p0
DBCP
BoneCp
Druid(阿里出品)
union和union all有什么区别
Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序;
Union All:对两个结果集进行并集操作,包括重复行,不进行排序
数据库客户端
navicat
数据同步
结构同步
创建备份计划
导出结果数据表
还原mysql数据库
导入数据表
创建和调用储存过程,函数
sqlyog
关系性数据库的三范式
1NF:原子性,字段不可分,否则就不再是关系型数据库
2NF:唯一性 一个表只说明一个事物;
3NF:每列都与主键有直接关系,不存在传递依赖;
java的数据库操作
如何通过jdbc访问数据库
a、加载(注册)数据库驱动(到JVM)
b、建立(获取)数据库连接。
c、创建(获取)数据库操作对象。
d、定义操作的SQL语句
e、执行数据库操作
f、获取并操作结果集
g、关闭对象,回收数据库资源(关闭结果集-->关闭数据库操作对象-->关闭连接)
JDBC事务管理
jdbc提供了三个方法进行事务管理
setAutoCommit()
commit() 提交事务
rollback() 回滚事务
jdbc的5种事务隔离级别
TRANSACTION_NONE(不支持事务)
TRANSACTION_READ_UNCOMMITTED
TRANSACTION_READ_COMMITTED
TRANSACTION_REPEATABLE_READ
TRANSACTION_SERIALIZABLE
除了TRANSACTION_NONE外,其它4种隔离级别 与 MySQL的事务隔离级别一样
JDBC原理与常用API
Connection
Statement
PreparedStatement
ResultSet
Class.forName的作用是什么
Statement,PreparedStatement和CallableStatement区别
getString和getObject的区别
使用jdbc需要注意哪些
什么是JDO
Jdbc与hibernate的区别
javaweb
JavaWeb基础
XML及其解析
DOM
SAX
jdom
dom4j
XStream
JAVA语言中常用字符编码方式
ISO-8859-1、(一般用于编码拉丁文)
GB2312、GBK、(一般用来编码简体中文)
UTF-8/UTF-16/UTF-32等。(使用最多,国际标准UNICODE编码方式)
servlet和jsp
servlet
什么是servlet
servlet是web开发中的一个标准,主要是交互式地浏览和修改数据,生成动态Web内容
什么是servlet的生命周期

doPost和doGet怎么选择
jsp
jsp有哪些优点

jsp与servlet的异同
servlet
 
jsp

本质

jsp的九大内置对象
输入输出对象:out对象、response对象、request对象
out对象:用于向客户端,浏览器输出数据
request对象:封装了来自客户端,浏览器的各种信息
response对象:封装了服务器的响应信息
通信控制对象:pageContext对象、session对象、application对象
pageContext对象:提供了对jsp页面的所有对象以及命名空间的访问
session对象:保存会话信息,也就是说,可以实现在同一用户的不同请求之间共享
application对象:代表了当前应用程序的上下文,可以在不同的用户之间共享信息
Servlet对象:page对象、config对象
page对象:指向了当前jsp程序本身
config对象:封装了应用程序的配置信息
错误处理对象:exception对象
exception对象:封装了jsp程序执行过程中发生的异常和错误信息
jsp四大作用域
page范围∶只在一个页面保留数据( javax.servlet.jsp.PageContext(抽象类))
request范围∶只在一个请求中保存数据(javax.servlet.httpServletRequest )
Session范围︰在一次会话中保存数据,仅供单个用户使用(javax.servlet.http.HttpSession)
Application范围∶在整个服务器中保存数据,全部用户共享(javax.servlet.ServletContext)
jsp中的七种基本动作
jsp中的include指令和include动作有什么区别
request对象主要有哪些方法

什么是ajax
tomcat
tomcat环境搭建
tomcat的目录层次结构

bin:存命令
conf:存配置
lib:存依赖
logs
temp
webapps
work
tomcat服务器配置
JavaWeb进阶
表达式语言
EL表达式
只能从四大作用域中获取数据
JSTL表达式(标准标签库)
jsp自定义标签
三种自定义标签的方式
通过tld文件,自定义方法标签
通过tag文件自定义控件标签
通过tld文件自定义判断标签,控件标签
异常处理
国际化
MVC三层架构
表现层
业务逻辑层
数据访问层
JavaWeb高级
监听器Listener
spring中的各种Listener
过滤器Filter
springmvc各种FIlter
文件上传与下载
springmvc中文件的上传,下载,删除
Java邮件服务JavaMail
邮件相关的标准
SMTP
POP3
IMAP
MIME
Java事务管理JTA
java基础知识
基本概念
java中的权限修饰符和作用域

需要注意的

一个java文件里面是否可以定义多个类?
可以,但是只有允许有一个类的名字与文件名相同
什么是构造函数?
构造函数必须与类的名字相同,并且不能有返回值(返回值也不能为void)
每个类可以有多个构造函数。当开发人员没有提供构造函数时,编译器在把源代码编译成字节码的过程中会提供一个没有参数默认的构造函数,但该构造函数不会执行任何代码。如果开发人员提供了构造函数,那么编译器就不会在创建默认的构造函数了。
构造函数总是伴随着new操作一起调用,且不能由程序的编写者直接调用,必须要由系统调用。构造函数在对象实例化时会被自动调用,且只运行一次;而普通的方法是在程序执行到它时被调用,且可以被对象调用多次。
构造函数,主要工作是完成对象的初始化
Java中创建对象的几种方式
使用new关键字
使用Clone的方法
无论何时我们调用一个对象的clone方法,JVM就会创建一个新的对象,将前面的对象的内容全部拷贝进去
使用反序列化
当我们序列化和反序列化一个对象,JVM会给我们创建一个单独的对象
使用反射
什么是反射
容器
List
ArrayList
默认大小是10,每次1.5倍
stack
vector
LinkedList
Set
hashset
请说一下hashset的实现原理

treeset
TreeSet可以确保集合元素处于排序状态
map
HashMap
初始容量为16,扩容每次乘以2
装载因子默认0.75
threshold是容量乘以装载因子
数组长度保持2的次幂,length-1的低位都为1, 会使得获得的数组索引index更加均匀
HashMap什么时候会进行扩容
1.7的源码
执行put方法的
if ((size >= threshold) && (null != table[bucketIndex])) {}
根据key的hash值,对数组的大小取模 hash & (length-1)
1.8的源码
putVal之后执行if (++size > threshold){}
扩容时不需要重新计算hash,关键看 原来的hash值新增的那个bit是1还是0
是0的话索引没变,是1的话索引变成“原索引+oldCap”
HashMap什么时候会进行rehash
扩容的过程中需要进行ReHash
HashMap线程不安全的体现
扩容造成死循环
https://www.jianshu.com/p/1e9cf0ac07f4
当在数组该位置get寻找对应的key时,就发生了死循环
put引发扩容,浪费内存
扩容时,删除不了
某个线程在删除某个元素时,发现删除不了, 因为table指向了新数组,且新数组还没有数据
2个同时put,导致1个丢失,被后1个put给覆盖掉了
在扩容的时候插入数据, 有可能会把新插入的覆盖住
在扩容时,在数据从旧数组复制到新数组过程中, 插入一条数据到新数组中,但数据复制过程中, HashMap是没有检查新数组上的位置是否为空, 新插入的数据会被后面从旧数组中复制过来的数据覆盖住
JDK1.8中HashMap的性能优化
HashMap在jdk1.8之后引入了红黑树的概念, 表示若桶中链表元素超过8时,会自动转化成红黑树; 若桶中元素小于等于6时,树结构还原成链表形式。
选择6和8的原因
中间有个差值7可以防止链表和树之间频繁的转换
HashMap1.7为什么使用的是头插法, 1.8后使用尾插法,这个改变有什么作用吗
JDK1.8之后是因为加入了红黑树使用尾插法, 能够避免出现逆序且链表死循环的问题
扩容时不需要重新计算hash,关键看 原来的hash值新增的那个bit是1还是0
是0的话索引没变,是1的话索引变成“原索引+oldCap”
Jdk1.8中没有indexFor函数,直接使用 table[index = (n – 1) & hash] (与运算交换左右,结果不变
TreeMap
适用于按自然顺序或自定义顺序遍历键(key)
TreeMap 的底层就是一颗红黑树
只能在单线程下安全使用
与hashmap的不同
HashMap的结果是没有排序的, 而TreeMap输出的结果是排好序的
ConcurrentSkipListMap
底层是通过跳表来实现的
适用于按自然顺序或自定义顺序遍历键(key)
多线程安全
HashTable
特点:锁住整个容器
与hashmap的不同
HashMap的key、value都可以为null
Hashtable的key、value都不可以为null
HashMap的函数则是非同步的,非线程安全的
hashTable是线程安全的
HashMap只支持Iterator(迭代器)遍历
Hashtable支持Iterator(迭代器)和 Enumeration(枚举器)两种方式遍历
Hashtable默认的“加载因子”是0.75, 默认的容量大小是11
初始size为11,扩容:newsize = olesize*2+1
WeakHashMap
与hashmap的不同
HashMap的“键”是强引用, WeakHashMap的键是弱引用
LinkedHashMap
与hashmap的不同
比 HashMap 多维护了一个双向链表
可以按照插入的顺序从头部或者从尾部迭代
内存相比而言要比 HashMap 大
ConcurrentHashMap
锁分段技术来保证线程安全的
1.7与1.8的区别
1.8使用Unsafe类的CAS自旋赋值+synchronized同步+ LockSupport阻塞等手段实现的高效并发
采用头插法
与hashmap的不同
Iterator和ListIterator
ListIterator有add()方法,可以向List中添加对象,而Iterator不能
iterator()方法在set和list接口中都有定义,ListIterator()仅存在于list接口中(或实现类中)
ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历
ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能
queue
PriorityQueue
fail-fast机制
集合结构上发生了改变(.remove(i))该机制将尽最大努力抛出异常
字符串与数组
字符串
字符串的创建和存储的机制是什么
通过双引号直接赋值
直接存储在"方法区"的“字符串常量池中”
通过构造器来创建
当我们new一个对象的时候,是在堆内存中开辟空间
== equals的区别

string stringBuffer StringBuilder的区别
区别
String
stringBuffer 线程安全
StringBuilder 线程不安全
相关题目
字符常量和字符串常量的区别

String s = new String("xyz");创建了几个字符串对象?
两个对象,一个是静态区的"xyz",一个是用new创建在堆上的对象。
String str="i"与 String str=new String("i")一样吗
不一样,因为内存的分配方式不一样。String str="i"的方式,Java 虚拟机会将其分配到常量池中;而 String str=new String("i") 则会被分到堆内存中。
数组
java中的数组是不是对象
数组的初始容量
数组的三种初始化方式

length属性和Length()方方的区别
length():获得字符串长度的方法
length:求数组长度的一个属性
基本类型与运算
java中的基本数据类型
数据类型的分类
数值型
整数型
byte 8 位,用于表示最小数据单位,如文件中数据,-128~127
short 16 位,很少用,-32768 ~ 32767
int 32 位、最常用,-2^31-1~2^31 (21 亿)
long 64 位、次常用 ,数据库的bigint----Long(一般主键的数据类型)
浮点型
float 单精度类型,32 位,后缀 F 或 f,1 位符号位,8 位指数,23 位有效尾数
double 64 位,最常用,后缀 D 或 d,1 位符号位,11 位指数,52 位有效尾数
字符型
char 16位,java字符使用Unicode编码
布尔型
boolean
相关题目
short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?
第一个是错的:1是int类型
第二个是对的
char 型变量中能不能存贮一个中文汉字,为什么?
可以:一个char是2个字节
float f=3.4;是否正确?
不正确。3.4是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成float f =3.4F;。
什么是不可变类
概念:不可变类是指,一旦一个类的对象被创建出来,在其整个生命周期中,它的成员变量就不能被修改.java平台的类库中包含许多不可变的类,
如何设计一个不可变类
主要以final关键字来实现
使类中所有的成员变量被final修饰
类中没有修改成员变量的方法,例如setXXX,可以提供一个带参的构造函数来初始化这些成员变量
确保类中的方法不会被重写.可以将类或者类中的方法定义为final的来实现
值传递和引用传递区别
值传递:只要是基本类型传递 都是值传递
引用传递:针对于基本类型进行封装,对封装进行传递,是引用传递
运算符的优先级
口诀:单目乘除为关系,逻辑三目后赋值
运算符的分类
单目:单目运算符+ –(负数) ++ -- 等
乘除:算数单目运算符* / % + -
为:位移单目运算符<< >>
关系:关系单目运算符> < >= <= == !=
逻辑:逻辑单目运算符&& || & | ^
三目:三目单目运算符A > B ? X : Y
后:无意义,仅仅为了凑字数
赋值:赋值=
Math类中的round ceil floor方法的功能
round
四舍五入的原理是在参数上加0.5然后进行下取整。Math.round(num)实际上是等价于Math.floor(num+0.5)
ceil
向上取整
floor
向下取整
++i 和 i++
位移操作
两种位移操作符
两种带符号的
左移 <<
右移 >>
一种无符号的
右移操作 >>>
设计模式
请说一下你知道哪些设计模式
单例模式
核心
将构造器私有化
分类
饿汉式(推荐-线程安全的):类加载到内存后,就会有一个单例,JVM保证线程安全

缺点:不管是否用到,类加载的时候就完成实例化
饱汉式:

为什么要添加synchronized关键字
工厂模式
适配器模式
观察者模式
面向对象的技术
面向对象和面向过程的区别?

面向对象的语言:java,c++,pyhton
面向对象有哪些特征
封装
属性,方法
继承
java只支持单继承
多态
多态的实现机制
该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定
Java中两种实现多态的形式
继承
接口
面向过程的语言:C
组合和继承有什么区别

组合:只需要对象的引用置于新类中即可
继承会得到父类中所有的域或方法
重载和覆盖的区别
重载
重载是通过不同的方法参数来区分的。
不能用方法的访问权限、返回值类型和抛出的异常类型来重载
对于继承,如果父类的方法是私有的,就不能再子类中实现重载,如果子类也定义一个同名的方法,那就是一个新的方法,不是重载了。
覆盖
派生类的覆盖方法必须要和基类中被覆盖的方法有相同的函数和参数
派生类的覆盖方法的返回值必须要和基类中覆盖方法的返回值相同。
派生类的覆盖方法的抛出异常必须和基类的抛出异常一致
基类中被覆盖的方法不能private,否则子类是定义了一个新的方法而不是覆盖
两者的区别
覆盖是子类和父类之间的关系,垂直关系;重载同一个类之间方法之间的关系,是水平关系
覆盖只能由一个方法或者只能由一对方法产生关系;重载是多个方法之间的关系
覆盖是根据对象类型(对象对应存储空间类型)来决定的;而重载关系是根据调用的实参表和形参表来选择方法体的
抽象类
抽象类和接口有什么异同
抽象类不一定要有抽象方法
相同点

不同点

抽象类能使用 final 修饰吗?
不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类
抽象类的意义

内部类有哪些
成员内部类
实例内部类
静态内部类
局部内部类
匿名内部类(属于局部内部类的一种)
this和supper的区别
如何获取父类的名称
super.getClass().getName()
java中的对象的定位方式
通过句柄方式访问

直接访问

面向对象的有点有哪些?

类的的组成和执行顺序

程序的加载顺序
如何实现在main()方法执行前输出“hello world”
静态代码块的加载优先于main方法

java程序的初始化顺序是怎样的?

构造方法可否能被重写?
不能被重写,只有继承关系才能重写,构造方法不能被重写,但是能被重载
关键字
变量命名的规则

break continue return的区别
break:用于完全结束循环
return:结束一个方法
contiue:只终止本次循环,接着开始下次循环
final,finally, finalize

assert有什么作用
assert的应用范围
检查控制流
检查输入参数是否有效
检查函数结果是否有效
检查程序不变量
static关键字
基本用法

volatile的三大特性
保证可见性

jvm关于同步的规定

可见性的代码验证

不保证原子性
禁止指令重排
instanceof有什么作用
Java中的一个双目运算符,用来测试一个对象是否为一个类的实例
strictfp的作用
一旦使用了关键字strictfp来声明某个类、接口或者方法时,那么在这个关键字所声明的范围内所有浮点运算都是精确的
package有什么作用?
1). 提供多层命名空间,解决命名冲突,通过使用package,使得处于不同package中的类可以存在相同的名字。 2). 对类按功能进行分类,使项目的组织更加清晰。
高级
jvm
Java内存模型
线程共享
方法区
堆
老年代
新生代
Eden
Survivor
Survivor
线程私有
java栈

本地方法栈
程序计数器
关于引用
引用类型
强
A a=new A()
软
数据库查询缓存
弱
WeakHashMap、ThreadLocalMap
虚
一个对象的引用有多个,该如何判断它的可达性
单弱多强
内存管理和垃圾回收
判断一个对象是否可被回收
引用计数
可达性分析(哪些可作为GC root)
虚拟机栈中引用的对象
本地方法栈中引用的对象
静态成员变量或者常量引用的对象
垃圾收集
垃圾收集器算法
复制
标记-整理
标记-清除
分代算法
垃圾收集器
老年代回收器
CMS
牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器
四个大致步骤
初始标记
仅仅只是标记一下GC Roots能直接关联到的对象
stop of world)
并发标记
进行GC Roots Tracing
重新标记
为了修正并发标记期间因用户程序继续运作而 导致标记产生变动的那一部分对象的标记记录
stop of world)
并发清理
使用的是标记-清除的算法实现的
Serial old
Parallen old
新生代回收器
serial
Parnew
Parallel Scavenge
整堆回收器
G1
一种兼顾吞吐量和停顿时间的 GC 实现,是 JDK 9 以后的默认 GC 选项
四个大致步骤
初始标记
并发标记
最终标记
stop of world):
筛选回收
G1从整体来看是基于“标记整理”算法实现的收集器; 从局部上来看是基于“复制”算法实现的
最大的特点是引入分区的思路,弱化了分代的概念
每个分区被标记了E、S、O和H,H表示这些Region存储的是巨型对象, 新建对象大小超过Region大小一半时,直接在新的一个或多个连续分区中分配, 并标记为H
内存泄漏(无法释放已申请的内存空间)
什么条件下会造成内存泄漏
对象可达但是无用
内存泄漏的场景
循环创建对象
各种连接没有及时释放资源
使用Jconsole查找内存泄漏
JVM的栈上分配与逃逸分析(Escape Analysis)
原本分配到堆上的对象分配到栈上
内存溢出(没有足够的内存供申请者使用)
虚拟机和本地方法栈溢出
堆溢出
方法区溢出
内存映像分析工具(eclipse)
对dump出来的堆转存快照
内存分配与回收策略
Minor gc
Major gc
Full gc
如何减少gc的次数
尽量少用静态变量
对象不用时最好显式置为null
增大堆的最大值设置
尽量使用stringBuffer而不是string,减少不必要的中间对象
经常使用的图片可以使用软引用类型
调用System.gc()会发生什么?
通知GC开始工作,但是GC真正开始的时间不确定.
JVM的调优
调优工具
jinfo
查看java进程的运行时jvm参数详细信息, 例如最大堆内存、使用的什么垃圾收集器等
jps
先要使用jps查看出当前有哪些Java进程, 获取该Java进程的id后再对该进程进行处理。
jmap(查看内存)
jmap -dump:live, format=b, file=fileName pid
用于生成堆转储快照文件(某一时刻的); 将内存使用情况导出到文件中, 再用jhat、MAT、VisualVM分析查看, 以便查找内存溢出原因
jmap -heap pid
查看heap的概要信息,GC使用的算法、 heap的配置及wise heap的使用情况.
jmap -histo[:live] pid
查看堆内存中的每个类的类名、实例数量、内存占用大小
Jstat(查看性能)
查看classloader,compiler,gc相关信息, 实时监控资源和性能 。jstat工具特别强大, 可以用来监视VM内存内的各种堆和非堆的大小及其内存使用量。
jhat
用于分析生成堆转储快照,一般结合jmap使用
jstack
jstack用于生成java虚拟机当前时刻的线程快照, 主要目的是定位线程出现长时间停顿的原因, 如线程间死锁、死循环、请求外部资源导致的长时间等待等。
jstack应用一: JVM调优之jstack找出最耗cpu的线程并定位代码
通过jvm 查看死锁
jstack -l jvm_pid
jconsole
内存监控和线程监控
提供 Java 某个进程的内存、线程、类加载、 jvm 概要以及 MBean 等的实时信息
检测线程死锁使用JDK给我们的的工具JConsole
VisualVM
集成了多个 JDK 命令行工具的可视化工具, 它能为您提供强大的分析能力
对 Java 应用程序做性能分析和调优。 这些功能包括生成和分析海量数据、跟踪内存泄漏、 监控垃圾回收器、执行内存和 CPU 分析,同时它还 支持在 MBeans 上进行浏览和操作
第三方调优工具
MAT(Memory Analyzer Tool),一个基于Eclipse的内存分析工具
GChisto
分析gc日志的工具,可以通过gc日志来分析: Minor GC、full gc的时间、频率等等, 通过列表、报表、图表等不同的形式来反应gc的情况
17 个 JVM 参数
verbose:gc
启动jvm的时候,输出jvm里面的gc信息
-XX:+printGC
打印的GC信息
-XX:+PrintGCDetails
打印GC的详细信息
-XX:+PrintGCTimeStamps
打印GC发生的时间戳
-X:loggc:log/gc.log
指定输出gc.log的文件位置
-XX:+PrintHeapAtGC
表示每次GC后,都打印堆的信息
-XX:+TraceClassLoading
监控类的加载
-XX:+PrintClassHistogram
跟踪参数
-Xmx -Xms
这个就表示设置堆内存的最大值和最小值
-Xmn
设置新生代的内存大小。
-XX:NewRatio
新生代和老年代的比例。比如:1:4,就是新生代占五分之一。
-XX:SurvivorRatio
设置两个Survivor区和eden区的比例。 比如:2:8 ,就是一个Survivor区占十分之一。
XX:+HeapDumpOnOutMemoryError
发生OOM时,导出堆的信息到文件。
-XX:+HeapDumpPath
表示,导出堆信息的文件路径。
-XX:OnOutOfMemoryError
当系统产生OOM时,执行一个指定的脚本 ,这个脚本可以是任意功能的。 比如生成当前线程的dump文件, 或者是发送邮件和重启系统。
-XX:PermSize -XX:MaxPermSize
设置永久区的内存大小和最大值; 永久区内存用光也会导致OOM的发生。
-Xss
设置栈的大小。栈都是每个线程独有一个, 所有一般都是几百k的大小。
new的对象如何不分配在堆而分配在栈上
方法逃逸

jvm内存溢出后,其他线程能运行吗?
64位的JVM当中,int的长度是多少?
Java中数据类型所占用的位数和平台无关,在 32 位和64位 的Java 虚拟机中,int 类型的长度都是占4字节.
异常处理
finally中的代码什么时候被执行
不被执行的情况

会被执行的情况

异常处理的原理是什么
运行时异常和普通异常的区别
常见的运行时异常

error和exception有什么区别?

并发
线程/进程/纤程(协程)
进程
进程同步机制
共享内存
套接字
消息队列
信号
用于通知接收进程某个事件已经发生
信号量
信号量是一个计数器,可以用来控制多个进程对共享资源的访问
管道
一种半双工的通信方式,数据只能单向流动, 而且只能在具有亲缘关系的进程间使用。 进程的亲缘关系通常是指父子进程关系
命名管道
有名管道也是半双工的通信方式, 它允许无亲缘关系进程间的通信
什么是进程
进程是资源分配的最小单位
进程的状态和转换
守护进程
守护进程就是在后台运行,不与任何终端关联的进程, 通常情况下守护进程在系统启动时就在运行, 它们以root用户或者其他特殊用户(apache和 postfix)运行,并能处理一些系统级的任务.
孤儿进程
如果父进程先退出,子进程还没退出那么子进程将被 托孤给init进程
僵尸进程
一个进程已经终止了,但是其父进程还没有获取其状态
如何避免
通过signal(SIGCHLD, SIG_IGN)通知内核对子进程的结束不关心,由内核回收。 如果不想让父进程挂起,可以在父进程中加入一条语句:signal(SIGCHLD,SIG_IGN); 表示父进程忽略SIGCHLD信号,该信号是子进程退出的时候向父进程发送的
fork两次,父进程fork一个子进程,然后继续工作, 子进程fork一个孙进程后退出,那么孙进程被init接管, 孙进程结束后,init会回收。不过子进程的回收还要自己做。
父进程通过wait和waitpid等函数等待子进程结束, 这会导致父进程挂起。
如果父进程很忙可以用signal注册信号处理函数,在信号处理函数调用wait/waitpid等待子进程退出
线程
创建线程的方式
四种创建线程方式
runnable
callable
future
future task
Callable接口的任务线程能返回执行结果
Thread
使用线程池例如用Executor框架
一个类可以同时继承Thread和实现Runnable接口
实现Callable接口的任务线程能返回执行结果; 而实现Runnable接口的任务线程不能返回结果
future的底层实现异步原理
提供了三种功能
判断任务是否完成
能够中断任务
能够获取任务执行结果
future的底层实现异步原理
在客户端请求的时候,直接返回客户端需要的数据 (此数据不一定完整,只是简单的一点不耗时的操作), 但是客户端并不一定马上使用所有的信息,此时就有了 时间去完善客户需要的信息
与FutureTask的区别和联系
future是个接口,futuretask可以通过实现该接口, 调用get方法返回执行结果
多线程中的i++线程安全吗?为什么?
分两种情况
如果i是局部变量
那么是线程安全的。因为局部变量是线程私有的,别的线程访问不到,其实也可以说没有线程安不安全之说,因为别的线程对他造不成影响。
如果i是全局变量
那么是线程不安全的。因为如果是全局变量的话,同一进程中的不同线程都有可能访问到。
如何线程安全的实现一个计数器?/ 有5个线程,每个线程作自增到1000
如何在Java中实现线程
继承Thread接口,重写run方法
实现Runnable接口,实现run方法
用Runnable还是Thread的区别
Runnable的实现方式是实现其接口即可
Thread的实现方式是继承其类
Runnable接口支持多继承,但基本上用不到
Thread实现了Runnable接口并进行了扩展,而Thread和Runnable的实质是实现的关系,不是同类东西,所以Runnable或Thread本身没有可比性。
实现callable接口,实现call方法
Java中的volatile的三大特性
保证可见性
主内存
工作内存
不保证原子性
禁止指令重排
什么是线程安全?Vector是一个线程安全类吗?
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量 的值也和预期的是一样的,就是线程安全的。一个线程安全的计数器类的同一个实例对象在被多个线程使用的情况下也不会出现计算失误。很显然你可以将集合类分 成两组,线程安全和非线程安全的。Vector 是用同步方法来实现线程安全的, 而和它相似的ArrayList不是线程安全的。
Java中如何停止一个线程
Java提供了很丰富的API但没有为停止线程提供API。JDK 1.0本来有一些像stop(), suspend() 和 resume()的控制方法但是由于潜在的死锁威胁因此在后续的JDK版本中他们被弃用了,之后Java API的设计者就没有提供一个兼容且线程安全的方法来停止一个线程。当run() 或者 call() 方法执行完的时候线程会自动结束,如果要手动结束一个线程,你可以用volatile 布尔变量来退出run()方法的循环或者是取消任务来中断线程。
一个线程运行时发生异常会怎样
这是我在一次面试中遇到的一个很刁钻的Java面试题, 简单的说,如果异常没有被捕获该线程将会停止执行。Thread.UncaughtExceptionHandler是用于处理未捕获异常造成线程突然中 断情况的一个内嵌接口。当一个未捕获异常将造成线程中断的时候JVM会使用Thread.getUncaughtExceptionHandler()来 查询线程的UncaughtExceptionHandler并将线程和异常作为参数传递给handler的uncaughtException()方法 进行处理。
如何在两个线程间共享数据
你可以通过共享对象来实现这个目的,或者是使用像阻塞队列这样并发的数据结构。这篇教程《Java线程间通信》(涉及到在两个线程间共享对象)用wait和notify方法实现了生产者消费者模型。
Java中notify 和 notifyAll有什么区别
这又是一个刁钻的问题,因为多线程可以等待单监控锁,Java API 的设计人员提供了一些方法当等待条件改变的时候通知它们,但是这些方法没有完全实现。notify()方法不能唤醒某个具体的线程,所以只有一个线程在等 待的时候它才有用武之地。而notifyAll()唤醒所有线程并允许他们争夺锁确保了至少有一个线程能继续运行。
为什么wait, notify 和 notifyAll这些方法不在thread类里面?
这是个设计相关的问题,它考察的是面试者对现有系统和一些普遍存在但看起来不合理的事物的看法。回答这些问题的时候,你要说明为什么把这些方法放在 Object类里是有意义的,还有不把它放在Thread类里的原因。一个很明显的原因是JAVA提供的锁是对象级的而不是线程级的,每个对象都有锁,通 过线程获得。如果线程需要等待某些锁那么调用对象中的wait()方法就有意义了。如果wait()方法定义在Thread类中,线程正在等待的是哪个锁 就不明显了。简单的说,由于wait,notify和notifyAll都是锁级别的操作,所以把他们定义在Object类中因为锁属于对象。
什么是ThreadLocal变量
ThreadLocal是Java里一种特殊的变量。每个线程都有一个ThreadLocal就是每个线程都拥有了自己独立的一个变量,竞争条件被 彻底消除了。它是为创建代价高昂的对象获取线程安全的好方法,比如你可以用ThreadLocal让SimpleDateFormat变成线程安全的,因 为那个类创建代价高昂且每次调用都需要创建不同的实例所以不值得在局部范围使用它,如果为每个线程提供一个自己独有的变量拷贝,将大大提高效率。首先,通 过复用减少了代价高昂的对象的创建个数。其次,你在没有使用高代价的同步或者不变性的情况下获得了线程安全。线程局部变量的另一个不错的例子是 ThreadLocalRandom类,它在多线程环境中减少了创建代价高昂的Random对象的个数。
为什么wait和notify方法要在同步块中调用?
主要是因为Java API强制要求这样做,如果你不这么做,你的代码会抛出IllegalMonitorStateException异常。还有一个原因是为了避免wait和notify之间产生竞态条件。
为什么你应该在循环中检查等待条件?
处于等待状态的线程可能会收到错误警报和伪唤醒,如果不在循环中检查等待条件,程序就会在没有满足结束条件的情况下退出。因此,当一个等待线程醒来 时,不能认为它原来的等待状态仍然是有效的,在notify()方法调用之后和等待线程醒来之前这段时间它可能会改变。这就是在循环中使用wait()方 法效果更好的原因,你可以在Eclipse中创建模板调用wait和notify试一试。如果你想了解更多关于这个问题的内容,我推荐你阅读《Effective Java》这本书中的线程和同步章节。
Java中的同步集合与并发集合有什么区别?
同步集合与并发集合都为多线程和并发提供了合适的线程安全的集合,不过并发集合的可扩展性更高。在Java1.5之前程序员们只有同步集合来用且在 多线程并发的时候会导致争用,阻碍了系统的扩展性。Java5介绍了并发集合像ConcurrentHashMap,不仅提供线程安全还用锁分离和内部分 区等现代技术提高了可扩展性
什么是线程池? 为什么要使用它?
创建线程要花费昂贵的资源和时间,如果任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限。为了避免这些问题,在程序启动的时 候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程。从JDK1.5开始,Java API提供了Executor框架让你可以创建不同的线程池。比如单线程池,每次处理一个任务;数目固定的线程池或者是缓存线程池(一个适合很多生存期短 的任务的程序的可扩展线程池)。
如何写代码来解决生产者消费者问题?
在现实中你解决的许多线程问题都属于生产者消费者模型,就是一个线程生产任务供其它线程进行消费,你必须知道怎么进行线程间通信来解决这个问题。比 较低级的办法是用wait和notify来解决这个问题,比较赞的办法是用Semaphore 或者 BlockingQueue来实现生产者消费者模型,这篇教程有实现它。
Java中synchronized 和 ReentrantLock 有什么不同
Java在过去很长一段时间只能通过synchronized关键字来实现互斥,它有一些缺点。比如你不能扩展锁之外的方法或者块边界,尝试获取锁 时不能中途取消等。Java 5 通过Lock接口提供了更复杂的控制来解决这些问题。 ReentrantLock 类实现了 Lock,它拥有与 synchronized 相同的并发性和内存语义且它还具有可扩展性
有三个线程T1,T2,T3,怎么确保它们按顺序执行
在多线程中有多种方法让线程按特定顺序执行,你可以用线程类的join()方法在一个线程中启动另一个线程,另外一个线程完成该线程继续执行。为了确保三个线程的顺序你应该先启动最后一个(T3调用T2,T2调用T1),这样T1就会先完成而T3最后完成。
Java中ConcurrentHashMap的并发度是什么
ConcurrentHashMap把实际map划分成若干部分来实现它的可扩展性和线程安全。这种划分是使用并发度获得的,它是 ConcurrentHashMap类构造函数的一个可选参数,默认值为16,这样在多线程情况下就能避免竞争用
Swing是线程安全的吗? 为什么?
你可以很肯定的给出回答,Swing不是线程安全的,但是你应该解释这么回答的原因即便面试官没有问你为什么。当我们说swing不是线程安全的常 常提到它的组件,这些组件不能在多线程中进行修改,所有对GUI组件的更新都要在AWT线程中完成,而Swing提供了同步和异步两种回调方法来进行更 新。
Swing API中那些方法是线程安全的?
这个问题又提到了swing和线程安全,虽然组件不是线程安全的但是有一些方法是可以被多线程安全调用的,比如repaint(), revalidate()。 JTextComponent的setText()方法和JTextArea的insert() 和 append() 方法也是线程安全的。
多线程中的忙循环是什么?
忙循环就是程序员用循环让一个线程等待,不像传统方法wait(), sleep() 或 yield() 它们都放弃了CPU控制,而忙循环不会放弃CPU,它就是在运行一个空循环。这么做的目的是为了保留CPU缓存,在多核系统中,一个等待线程醒来的时候可 能会在另一个内核运行,这样会重建缓存。为了避免重建缓存和减少等待重建的时间就可以使用它了。
如何强制启动一个线程?
这个问题就像是如何强制进行Java垃圾回收,目前还没有觉得方法,虽然你可以使用System.gc()来进行垃圾回收,但是不保证能成功。在Java里面没有办法强制启动一个线程,它是被线程调度器控制着且Java没有公布相关的API。
Java多线程中调用wait() 和 sleep()方法有什么不同
Java程序中wait 和 sleep都会造成某种形式的暂停,它们可以满足不同的需要。wait()方法用于线程间通信,如果等待条件为真且其它线程被唤醒时它会释放锁,而 sleep()方法仅仅释放CPU资源或者让当前线程停止执行一段时间,但不会释放锁。
线程池
如果你提交任务时,线程池队列已满。会时发会生什么
这个问题问得很狡猾,许多程序员会认为该任务会阻塞直到线程池队列有空位。事实上如果一个任务不能被调度执行那么ThreadPoolExecutor’s submit()方法将会抛出一个RejectedExecutionException异常
Java线程池中submit() 和 execute()方法有什么区别
两个方法都可以向线程池提交任务,execute()方法的返回类型是void,它定义在Executor接口中, 而submit()方法可以返回持有计算结果的Future对象,它定义在ExecutorService接口中,它扩展了Executor接口,其它线 程池类像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有这些方法。
线程中的堆栈
Java中堆和栈有什么不同?
为什么把这个问题归类在多线程和并发面试题里?因为栈是一块和线程紧密相关的内存区域。每个线程都有自己的栈内存,用于存储本地变量,方法参数和栈 调用,一个线程中存储的变量对其它线程是不可见的。而堆是所有线程共享的一片公用内存区域。对象都在堆里创建,为了提升效率线程会从堆中弄一个缓存到自己 的栈,如果多个线程使用该变量就可能引发问题,这时volatile 变量就可以发挥作用了,它要求线程从主存中读取变量的值。
你如何在Java中获取线程堆栈
对于不同的操作系统,有多种方法来获得Java进程的线程堆栈。当你获取线程堆栈时,JVM会把所有线程的状态存到日志文件或者输出到控制台。在 Windows你可以使用Ctrl + Break组合键来获取线程堆栈,Linux下用kill -3命令。你也可以用jstack这个工具来获取,它对线程id进行操作,你可以用jps这个工具找到id。
JVM中哪个参数是用来控制线程的栈堆栈小的
这个问题很简单, -Xss参数用来控制线程的堆栈大小。
线程锁问题
如何避免死锁?
Java多线程中的死锁 死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,死锁的发生必须满足以下四个条件: 互斥条件:一个资源每次只能被一个进程使用。 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。 避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁。
Java中活锁和死锁有什么区别?
这是上题的扩展,活锁和死锁类似,不同之处在于处于活锁的线程或进程的状态是不断改变的,活锁可以认为是一种特殊的饥饿。一个现实的活锁例子是两个 人在狭小的走廊碰到,两个人都试着避让对方好让彼此通过,但是因为避让的方向都一样导致最后谁都不能通过走廊。简单的说就是,活锁和死锁的主要区别是前者 进程的状态可以改变但是却不能继续执行。
怎么检测一个线程是否拥有锁?
我一直不知道我们竟然可以检测一个线程是否拥有锁,直到我参加了一次电话面试。在java.lang.Thread中有一个方法叫holdsLock(),它返回true如果当且仅当当前线程拥有某个具体对象的锁。
线程的状态
线程调度器
负责为runnable状态线程分配cpu时间
线程同步机制
临界区
指的是一个访问共用资源(例如:共用设备或是共用存储器) 的程序片段,而这些共用资源又无法同时被多个线程访问的特性
互斥量
锁
信号量
volatile
事件
选择器epoll()
java线程的分类
守护线程,比如垃圾回收线程,就是最典型的守护线程
用户线程,就是应用程序里的自定义线程
什么是线程
线程是执行的最小单位
协程
线程和进程的区别
线程池
管理一组工作线程
等待执行任务的消息队列
创建线程池的方式
创 建 线 程 池
newSingleThreadExecutor (单线程线程池)
适用场景
适用于串行执行任务的场景
newFixedThreadPool (固定大小线程池)
特点
coresize和maxsize相同
队列用的LinkedBlockingQueue无界
keepAliveTime为0
工作机制
1.线程数少于核心线程数,新建线程执行任务
2.线程数等于核心线程数后,将任务加入阻塞队列
3.执行完任务的线程反复去队列中取任务执行
适用场景
适用于处理CPU密集型的任务, 确保CPU在长期被工作线程使用的情况下, 尽可能的少的分配线程即可。一般Ncpu+1
newCachedThreadPool (可缓存线程的线程池)
特点
核心线程数为0,且最大线程数为Integer.MAX_VALUE
阻塞队列是SynchronousQueue
keepAliveTime为60s
工作机制
1.没有核心线程,直接向SynchronousQueue中提交任务
2如果有空闲线程,就去取出任务执行; 如果没有空闲线程,就新建一个
3.执行完任务的线程有60秒生存时间, 如果在这个时间内可以接到新任务, 就继续,否则结束生命
适用场景
用于并发执行大量短期的小任务
newScheduledThreadPool (定长、周期性执行任务)
特点
最大线程数为Integer.MAX_VALUE
阻塞队列是DelayedWorkQueue
工作机制
1.线程从 DelayQueue 中获取 time 大于等于当前时间的 ScheduledFutureTask(DelayQueue.take())
2.执行完后修改这个 task 的 time 为下次被执行的时间
3.再把这个 task 放回队列中
适用场景
用于需要多个后台线程执行周期任务, 同时需要限制线程数量的场景。
两种启动线程池的方法:submit(有返回值)和execute(无返回值)
线程池的核心
生产者消费者模型
生产者将需要处理的任务放入队列
消费者从任务队列中取出任务处理
线程池的参数(ThreadPoolExecutor)
maximumPoolSize:最大线程数
corePollSize:核心线程数
keepAliveTime:空闲的线程保留的时间
workQueue任务队列): 用于保存等待执行的任务的阻塞队列
ThreadFactory
用于设置创建线程的工厂,可以通过线程工厂给每个 创建出来的线程做些更有意义的事情,比如设置daemon和优先级等等
RejectedExecutionHandler(饱和策略)
AbortPolicy:直接抛出异常。
CallerRunsPolicy:只用调用者所在线程来运行任务。
DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
DiscardPolicy:不处理,丢弃掉。
TimeUnit:空闲线程的保留时间单位
单机上一个线程正在处理服务,如果忽然断电了怎么办 (正在处理和阻塞队列里的请求怎么处理)
阻塞队列持久化,正在处理事物控制。断电之后正在处理的回滚, 日志恢复该次操作。服务器重启后阻塞队列中的数据再加载
线程池关闭相关操作
shutdown
shutdown()后线程池将变成shutdown状态,此时不接收新任务, 但会处理完正在运行的 和 在阻塞队列中等待处理的任务。
shutdownNow
shutdownNow()后线程池将变成stop状态,此时不接收新任务, 不再处理在阻塞队列中等待的任务,还会尝试中断正在处理中的工作线程。
多线程
线程池
为什么要使用线程池
1. 降低资源消耗。 2. 提高响应速度。 3. 提高线程的可管理性。
常见的线程池有哪些

同步和异步有什么区别
如何实现java的多线程
继承Thread接口,重写run方法
实现Runnable接口,实现run方法
实现Callable接口,实现call方法
run()方法和start()方法的区别
run()方法:是在主线程中执行方法,和调用普通方法一样;(按顺序执行,同步执行)
start()方法:是创建了新的线程,在新的线程中执行;(异步执行)
多线程同步的实现方法
同步方法
同步代码块
使用特殊域变量(volatile)实现线程同步
使用重入锁实现线程同步
使用局部变量实现线程同步
java终止线程的三种方式
使用退出标志,使线程正常退出,也就是当 run() 方法完成后线程中止
使用 stop() 方法强行终止线程,但是不推荐使用这个方法,该方法已被弃用
使用 interrupt 方法中断线程
sleep()和wait
sleep是Thread类的方法,sleep方法只让出了CPU,而并不会释放同步资源锁 当sleep()结束指定休眠时间后,不一定立即执行,此时其他线程可能正在运行
wait方法是Object类里的方法,线程执行到wait()方法后,进入待池中, 同时释放了锁对象,必须调用notify或者notifyAll方法才能唤醒,而且是随机唤醒, 若是被其他线程抢到了CPU执行权,该线程会继续进入等待状态
是否可以传入参数
sleep()方法必须传入参数,参数就是休眠时间
wait()方法可以传入参数也可以不传入参数, 传入参数就是在参数结束的时间后开始等待
是否需要捕获异常
sleep方法必须要捕获异常
wait方法不需要捕获异常
作用范围
wait、notify和notifyAll方法只能在同步方法或者同步代码块中使用
sleep方法可以在任何地方使用,注意sleep是静态方法,也就是说它只对当前对象有效
调用者的区别
wait和notify、notifyAll方法是由确定的对象即锁对象来调用的, 先对某个线程说停下来等待,然后对另一个线程说可以执行了
sleep方法是让某个线程暂停运行一段时间,其控制范围是由当前线程决定, 运行的主动权是由当前线程来控制(拥有CPU的执行权)
本质的区别一个是线程的运行状态控制,一个是线程间的通信
介绍一下Syncronized锁
修饰一个代码块
作用的范围:是大括号{}括起来的代码
作用的对象:是调用这个代码块的对象
修饰一个非静态方法
作用的范围:整个方法
作用的对象:调用这个方法的对象
解释:也就是说调用这个方法的对象,如果里面有很多被synchronized 修饰方法情况下,有一个被调用其他的都得等着(但是不包含synchronized 静态方法).
修饰一个静态方法
作用的范围:整个静态方法
作用的对象:这个类的所有对象
解释:此类所有对象(被new出了好几个对象)有多个被synchronized 修饰静态方法情况下,只要是有一个对象中一个静态方法被占用,其他所有对象中所有静态方法都得等着(但是不包含synchronized 普通方法).
修饰一个类
作用的范围:synchronized后面括号括起来的部分
作用的对象:这个类的所有对象
解释:没啥说的,就是一个类都锁了,不管什么方法,不管几个对象,一个吊用,其他都锁.
补充
修饰非静:这个就是对象锁(一个对象中有两个方法同时被synchronized,调用这两个方法时,只能同时执行一个。但它并不能使调用该方法的多个对象在执行顺序上互斥,就是多个对象调用这个方法它就没办法保证数据是不是出现同时被使用脏读这些问题,不知道描述精准吗,请大佬指正)
修饰静:这个就是类锁了,一锁锁一个类的所有对象.
修饰非静与修饰静,出现在同一个对象中他们不是一个锁, 各走各的,相互不影响
Syncronized的基本介绍
它属于Java中关键字,是一种jvm级别锁
synchronized锁不需要手动释放,哪怕是代码出现异常,jvm也能自动释放锁
Syncronized的优缺点
优点
缺点
synchronized与Lock有什么异同
volatile
可见性
底层是共享变量
禁止重排序
内存屏障
LoadLoad
StoreStore
LoadStore
StoreLoad
内部实现机制
volatile变量修饰的共享变量的Java代码转换成汇编代码,会有lock 修饰
将当前内核高速缓存行的数据立刻回写到内存
使在其他内核里缓存了该内存地址的数据无效
MESI协议,该解决缓存一致性的思路是:当CPU写数据时,如果发现操作的变量是共享 变量,即在其他CPU中也存在该变量的副本,那么他会发出信号通知其他CPU将该变量 的缓存行设置为无效状态。当其他CPU使用这个变量时,首先会去嗅探是否有对该变量更 改的信号,当发现这个变量的缓存行已经无效时,会从新从内存中读取这个变量。
无锁化编程实现线程安全
final(数据不可修改)
CAS
原子类
Copy-on-write
如何判断一个线程是否拥有锁
Thread的holdsLock方法
java中的锁
锁优化
减少锁的持有时间
减少锁得用于粒度
锁分离
读锁
写锁
锁粗化
如果一段程序要多次请求锁,锁之间的代码执行时间比较少,就应该整合成一个锁
自旋锁(不可重入锁)
锁清除
堆检测到不可能存在共享数据竞争的锁进行清除(逃逸分析技术)
锁降级
指的是把持住(当前拥有的)写锁,再获取到读锁,随后释放(先前有用的)写锁的过程
读写锁
写独占,读共享,写锁优先级高(本质上是一种自旋锁)
乐观锁(适用于大并发量)
CAS
atomic
悲观锁(适用于并发量不大的场景)
Lock
悲观锁、可中断锁、可公平锁、可重入锁)
synchronized
悲观锁、不可中断锁、非公平锁、可重入锁)
底层通过操作系统的互斥量实现,适用于竞争不激烈的场景
可重入锁和不可重入锁(自旋锁)
可重入锁实现原理:当一个线程请求成功后,JVM会记下持有锁的线程, 并将计数器计为1。此时其他线程请求该锁,则必须等待; 而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增
锁的状态
无锁状态
偏向锁状态
偏向锁是指一段同步代码一直被一个线程所访问, 那么该线程会自动获取锁。降低获取锁的代价。
轻量级锁状态
轻量级锁是指当锁是偏向锁的时候,被另一个线程 所访问,偏向锁就会升级为轻量级锁,其他线程会 通过自旋的形式尝试获取锁,不会阻塞,提高性能。
重量级锁状态
重量级锁是指当锁为轻量级锁的时候,另一个线程虽然是自旋, 但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁, 就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让其他申请的线 程进入阻塞,性能降低。
ThreadLocal
相当于一个容器,用于存放每个线程的局部变量
底层也是封装了ThreadLocalMap集合类来绑定当 前线程和变量副本的关系,各个线程独立并且访问安全
为什么ThreadLocalMap的 Entry是一个weakReference?
能够在下次gc时被回收,回收后的空间能够 得到复用,在一定程度下能够避免内存泄露
还适用的场景
数据库连接、Session管理
notify和notifyAll
唤醒一个或多个正处于等待状态的线程
什么是守护线程
java中线程分为两类
守护线程:比如垃圾回收线程,就是最典型的守护线程
用户线程:就是应用程序里的自定义线程
守护线程:专门用于服务其他的线程
特点:用户线程执行完毕,守护线程也终止运行
join()方法的作用是什么
阻塞队列
支持两个附加操作
当队列满时,存储元素的线程会等待队列可用
当队列空时,获取元素的线程会等待队列变为非空
阻塞队列先设定大小,防止内存溢出
线 程 池 队 列
ArrayBlockingQueue (有界队列)
是一个基于数组结构的有界阻塞队列, 此队列按 FIFO(先进先出)原则对元素进行排序
可以指定缓存队列的大小,当正在执行的线程数等于corePoolSize时,多余的 元素缓存在ArrayBlockingQueue队列中等待有空闲的线程时继续执行,当 ArrayBlockingQueue已满时,加入ArrayBlockingQueue失败,会开启新的 线程去执行,当线程数已经达到最大的maximumPoolSizes时,再有新的元素 尝试加入ArrayBlockingQueue时会报错
LinkedBlockingQueue (无界队列)
一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法 Executors.newFixedThreadPool()使用了这个队列。
maximumPoolSizes为无效
当前执行的线程数量达到corePoolSize的数量时, 剩余的元素会在阻塞队列里等待
SynchronousQueue (同步队列)
一个不存储元素的阻塞队列。每个插入操作必须等到 另一个线程调用移除操作,否则插入操作一直处于阻塞状态, 吞吐量通常要高于LinkedBlockingQueue,静态工厂方法 Executors.newCachedThreadPool使用了这个队列。
maximumPoolSizes为无界
使用SynchronousQueue阻塞队列一般要求 maximumPoolSizes为无界,避免线程拒绝执行操作
特点
SynchronousQueue 队列中没有任何缓存的数据, 可以理解为容量为 0
SynchronousQueue 提供两种实现方式, 分别是 栈 和 队列 的方式实现。这两种实现方式中, 栈 是属于非公平的策略,队列 是属于公平策略
DelayQueue (延迟队列)
一个任务定时周期的延迟执行的队列。 根据指定的执行时间从小到大排序, 否则根据插入到队列的先后排序。
PriorityBlockingQueue(优先级队列)
一个具有优先级得无限阻塞队列
判断线程是否停止的方法interrupted 和isinterrupted的区别
interrupted
静态方法
作用于当前正在运行的线程
会清除线程中断状态
isinterrupted
非静态方法
作用于该方法的调用对象所对应的线程
三个线程交替顺序打印ABC
使用synchronized, wait和notifyAll
使用Lock->ReentrantLock 和 state标志
使用Lock->ReentrantLock 和 Condition(await 、signal、signalAll)
使用Semaphore
使用AtomicInteger
缓存一致性问题
加lock锁
缓存一致性协议
lock 指令前缀
当使用 LOCK 指令前缀时,它会使 CPU 宣告一个 LOCK# 信号, 确保互斥地使用这个内存地址,当指令执行完毕,锁消失
lock前缀指令相当于一个内存屏障,会强制将对缓存的修改操作写入主内存
处理器的嗅探技术
每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了, 当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置为无效态, 当处理器对这个数据进行修改操作的时候,会重新从系统内存中吧数据读到处理器缓存里
happens-before原则
如果前一个操作(A)必须要对后一个操作(C)可见 ,那么这两个操作(A C) 指令不能重排
高并发系统限流中的算法
漏桶算法
一个固定容量的漏桶,按照固定常量速率流出请求, 流入请求速率任意,当流入的请求数累积到漏桶容量时, 则新流入的请求被拒绝
令牌桶算法
一个存放固定容量令牌的桶,按照固定速率往桶里添加令牌, 填满了就丢弃令牌,请求是否被处理要看桶中令牌是否足够, 当令牌数减为零时则拒绝新的请求
计数器限流算法
用来限制一定时间内的总并发数, 比如数据库连接池、线程池、秒杀的并发数
并发和并行的区别
 
输入输出流
java IO流的实现机制是什么
java中的IO体系
流式部分
字节流
InputStream
OutputStream
字符流
writer
Reader
非流式
File
Files的常用方法都有哪些?

RandomAccessFile
其他
管理文件和目录的类是什么
java socket是什么
javaNIO是什么
什么是java的序列化
system.out.print()方法使用的时候注意什么
java平台与内存管理
jvm加载class文件的原理机制
java是否存在内存泄漏的问题
java中的堆和栈的区别
跨域问题
关于同源策略
浏览器的同源策略

如果没有同源策略会怎么样?

同源策略限制了哪些行为

怎么实现CORS
通过JSONP
利用反向代理服务器
服务端支持CORS
通过CrossOrigin注解

通过CorsRegistry设置全局跨域配置
通过CorsFilter设置全局跨域配置
常用工具类API
字符串类

正则表达式的使用
正则表达式的语法
字符串的取值范围
1. [abc] : 表示可能是a,可能是b,也可能是c。 2.[ ^abc]: 表示不是a,b,c中的任意一个 3. [a-zA-Z]: 表示是英文字母 4. [0-9]:表示是数字
简洁的字符表示
.:匹配任意的字符 \d:表示数字 \D:表示非数字 \s:表示由空字符组成,[ \t\n\r\x\f] \S:表示由非空字符组成,[^\s] \w:表示字母、数字、下划线,[a-zA-Z0-9_] \W:表示不是由字母、数字、下划线组成
数量表达式
1.?: 表示出现0次或1次 2.+: 表示出现1次或多次 3.*: 表示出现0次、1次或多次 4.{n}:表示出现n次 5.{n,m}:表示出现n~m次 6.{n,}:表示出现n次或n次以上
逻辑表达式
1.XY: 表示X后面跟着Y,这里X和Y分别是正则表达式的一部分 2.X|Y:表示X或Y,比如"food|f"匹配的是foo(d或f),而"(food)|f"匹配的是food或f 3.(X):子表达式,将X看做是一个整体
正则表达式类
分别是java.util.regex下的Pattern类和Matcher类 在实际的开发中,为了方便我们很少直接使用Pattern类或Matcher类,而是使用String类下的方法 验证:boolean matches(String regex) 拆分: String[] split(String regex) 替换: String replaceAll(String regex, String replacement)
pattern
matcher
日期时间类
java.util.Date
java.sql.Date
java.sql.Time
java.sql.Timestamp
java.util.Calendar
System类
这个类中常用的方法
常见面试题
object有那些公用方法

java中的数据加密
需要密钥
对称加密
DES
3DES
AES
非对称加密
RSA
DSA
不需要密钥
又称哈希算法,散列算法
摘要算法
SHA-1
MD5
数据结构与算法
数据结构
链表
链表的简介

链表中的一些操作问题
如何实现链表的增删操作
如何从链表中删除重复的数据
如何实现链表的反转
如何从尾到头输出单链表
如何寻找单链表的中间结点
链表的分类
单向链表

双向链表

LinkedList 其实是一个双向链表,因为它定义了两个指针 next 和 prev 分别用来指向自己的下一个和上一个节点
双向链表每个节点由三部分组成
prev指针指向前置节点
此节点的数据和
next指针指向后置节点
循环链表
单循链表

双循链表

链表的组成
数据域:用于存储数据
指针域:用于指向下一个节点
链表反转的方式
用栈(stack)实现
图解用栈实现

代码实现

用递归的方式来实现
图解实现

代码实现

用循环的方式来实现
代码实现方式

栈和队列
栈与队列的区别
队列先进先出,栈先进后出
对插入和删除操作的"限定"不同

遍历数据速度不同

栈
栈的定义

栈的常用操作

栈是怎么实现的
队列
队列的定义
队列的基本操作
队列怎么实现的
排序
排序
插入排序
选择排序
直接选择排序
平均时间复杂度O(n2)
空间复杂度O(1)
不稳定排序
堆排序
平均时间复杂度O(nlgn)
空间复杂度O(1)
不稳定排序
代码实现

交换排序
冒泡排序
平均时间复杂度O(n2)
空间复杂度O(1)
稳定排序
快速排序
平均时间复杂度O(nlgn)
空间复杂度O(1)
不稳定排序
归并排序
平均时间复杂度O(nlgn)
空间复杂度O(n)
稳定排序
堆排序
从(array.length-2)/2开始到0构造堆
调用Adjustheap,dad=start,end,son
从0至array.length-1,依次把最大的移至数组尾
两指针之三色排序
如何进行堆排序
各种排序运算的优劣
数组
如何寻找数组中的最大值和最小值
如何找出数组中第二大的值
如何找出数组中的重复元素
如何求数组中两两相加等于20的组合的种数
字符串
算法
java中常用的运算符
算数运算符

赋值运算符

比较运算符

逻辑运算符

条件运算符

java中运算符的优先级

关于数组
已知一个排序好的带重复数字的数组1,和移动X位后的数组2,求X的值,要求复杂度
二分
给一个数组构造二叉排序树
https://blog.csdn.net/Yabber0914/article/details/52668663
找数组a中出现b中没出现的
hashset
找出两个整型数组中的公共元素的最大值
https://www.cnblogs.com/hapjin/p/5875108.html
找出数组中两个元素异或的最大值
https://leetcode.com/problems/maximum-xor-of-two-numbers-in-an-array/
一个n*n的二维数组,在原数组上将其顺时针旋转90度后输出
题目意思
解题代码
一个数组,除了某个数字只出现一次,其它都只出现两次,找出那个只出现了一次的元素
开发中的安全防范
攻击与防御
sql注入攻击
SQL注入攻击中以SQL语句作为用户输入,从而达到查询/修改/删除数据的目的
如何避免 sql 注入?
PreparedStatement(简单又有效的方法)
使用正则表达式过滤传入的参数
XSS 攻击
什么是 XSS 攻击
XSS 攻击,即跨站脚本攻击(Cross Site Scripting),它是 web 程序中常见的漏洞。
攻击的原理

xss攻击的种类
DOM Based XSS:基于网页 DOM 结构的攻击
如何避免
对输入(和URL参数)进行过滤,对输出进行编码
DDOS攻击原理与防御方式
SYN flood:伪造ip地址发送请求,占满半连接队列, 导致正常链接被服务器抛弃。攻击方需要很高的带宽资源
ACK flood:大量ACK连接请求服务器,服务器需要花费CPU资源 去查询连接队列并回应。只有当流量很高时才会对服务器造成影响
Connection Flood:利用真实IP,在服务器上建立大量连接, 从而占满服务器连接队列,导致正常连接被丢弃
HTTP Get Flood:发送大量会产生sql查询的连接, 使得数据库负载很高
如何预防csrf攻击
加密解密算法
需要密钥
对称加密
DES
3DES
AES
非对称加密
RSA
DSA
不需要密钥
摘要算法
SHA-1
MD5
幂等机制
怎么防止重复下订单
开发中用到的技术
git相关
git工作流程
1.克隆 Git 资源作为工作目录。
2.在克隆的资源上添加或修改文件
3.如果其他人修改了,你可以更新资源。
4.在提交前查看修改
5.提交修改
6.在修改完成后,如果发现错误,可以撤回提交并再次修改并提交
git的基本概念
.git文件

ignore文件

工作区
暂存区

本地仓库

远程仓库
新建代码仓库
git init
在当前目录新建一个Git代码库
git init [project-name]
git clone [url]
下载一个项目和它的整个代码历史
配置
显示当前的Git配置
git config --list
编辑Git配置文件
git config -e [--global]
设置提交代码时的用户信
git config [--global] user.name "[name]"
git config [--global] user.email "[email address]"
增删文件
git add
git add [file1] [file2] ...
添加指定文件到暂存区
git add [dir]
添加指定目录到暂存区,包括子目录
git add .
子主题
git add -p
添加每个变化前,都会要求确认
git rm
git rm [file1] [file2] ...
删除工作区文件,并且将这次删除放入暂存区
git rm --cached [file]
停止追踪指定文件,但该文件会保留在工作区
git mv [file-original] [file-renamed]
改名文件,并且将这个改名放入暂存区
代码提交
git commit -m [message]
提交暂存区到仓库区
git commit [file1] [file2] ... -m [message]
提交暂存区的指定文件到仓库区
git commit -a
提交工作区自上次commit 之后的变化,直接到仓库区
git commit -v
提交时显示所有diff信息
git commit --amend -m [message]
使用一次新的commit, 替代上一次提交
git commit --amend [file1] [file2] ...
重做上一次commit,并包 括指定文件的新变化
分支
git branch
列出所有本地分支
git branch -r
列出所有远程分支
git branch -a
列出所有本地分支和远程分支
git branch [branch-name]
新建一个分支,但依然停留在当前分支
git checkout -b [branch]
新建一个分支,并切换到该分支
git branch [branch] [commit]
新建一个分支,指向指定commit
git branch --track [branch] [remote-branch]
新建一个分支,与指定 的远程分支建立追踪关系
git checkout [branch-name]
切换到指定分支,并更新工作区
git checkout -
切换到上一个分支
git branch --set-upstream [branch] [remote-branch]
建立追踪关系,在现有分 支与指定的远程分支之间
git merge [branch]
合并指定分支到当前分支
git cherry-pick [commit]
选择一个commit,合并进当前分支
git branch -d [branch-name]
删除分支
删除远程分支
git push origin --delete [branch-name]
git branch -dr [remote/branch]
标签
git tag
列出所有tag
git tag [tag]
新建一个tag在当前commit
git tag [tag] [commit]
新建一个tag在指定commit
git tag -d [tag]
删除本地tag
git push origin :refs/tags/[tagName]
删除远程tag
git show [tag]
查看tag信息
git push [remote] [tag]
提交指定tag
git push [remote] --tags
提交所有tag
git checkout -b [branch] [tag]
新建一个分支,指向某个tag
查看信息
git status
显示有变更的文件
git log
显示当前分支的版本历史
git log --stat
显示commit历史,以及每次commit发生变更的文件
git log -S [keyword]
搜索提交历史,根据关键词
git log [tag] HEAD --pretty=format:%s
显示某个commit之后的所有 变动,每个commit占据一行
git log [tag] HEAD --grep feature
显示某个commit之后的所有变动 ,其"提交说明"必须符合搜索条件
显示某个文件的版本历 史,包括文件改名
git log --follow [file]
git whatchanged [file]
git log -p [file]
显示指定文件相关的每一次diff
git log -5 --pretty --oneline
显示过去5次提交
git shortlog -sn
显示所有提交过的用户,按提交次数排序
git blame [file]
显示指定文件是什么 人在什么时间修改过
git diff
显示暂存区和工作区的差异
git diff --cached [file]
显示暂存区和上一个commit的差异
git diff HEAD
显示工作区与当前分支最 新commit之间的差异
git diff [first-branch]...[second-branch]
显示两次提交之间的差异
git diff --shortstat "@{0 day ago}"
显示今天你写了多少行代码
git show [commit]
显示某次提交的元数据和内容变化
git show --name-only [commit]
显示某次提交发生变化的文件
git show [commit]:[filename]
显示某次提交时,某个文件的内容
git reflog
显示当前分支的最近几次提交
远程同步
git fetch [remote]
下载远程仓库的所有变动
git remote -v
显示所有远程仓库
git remote show [remote]
显示某个远程仓库的信息
git remote add [shortname] [url]
增加一个新的远程仓库,并命名
git pull [remote] [branch]
取回远程仓库的变化,并与本地分支合并
git push [remote] [branch]
上传本地指定分支到远程仓库
git push [remote] --force
强行推送当前分支到远程仓库,即使有冲突
git push [remote] --all
推送所有分支到远程仓库
撤销
git checkout [file
恢复暂存区的指定文件到工作区
git checkout [commit] [file]
恢复某个commit的指 定文件到暂存区和工作区
git checkout .
恢复暂存区的所有文件到工作区
git reset [file]
重置暂存区的指定文件,与上一次 commit保持一致,但工作区不变
git reset --hard
重置暂存区与工作区,与 上一次commit保持一致
git reset [commit]
重置当前分支的指针为指定commit, 同时重置暂存区,但工作区不变
git reset --hard [commit]
重置当前分支的HEAD为指定commit,同时 重置暂存区和工作区,与指定commit一致
git reset --keep [commit]
重置当前HEAD为指定commit, 但保持暂存区和工作区不变
git revert [commit]
新建一个commit,用来撤销指定commit 后者的所有变化都将被前者抵消, 并且应用到当前分支
暂时将未提交的变化移除,稍后再移入
git stash
git stash pop
其他
git archive
生成一个可供发布的压缩包
fetch和merge和pull的区别
pull相当于git fetch 和 git merge的组合, 即更新远程仓库的代码到本地仓库, 然后将内容合并到当前分支
git fetch:相当于是从远程获取 最新版本到本地,不会自动merge
git merge : 将内容合并到当前分支
git pull:相当于是从远程获 取最新版本并merge到本地
git merge和git rebase的区别
git merge branch会把branch分支的差 异内容pull到本地,然后与本地分支的内 容一并形成一个committer对象提交 到主分支上,合并后的分支与主分支一致;
git rebase branch会把branch分支优先合并 到主分支,然后把本地分支的commit放到主分 支后面,合并后的分支就好像从合并后主分支又 拉了一个分支一样,本地分支本身不会保留提交历史
HEAD、工作树和索引之间的区别
HEAD文件包含当前分支的引用(指针)
工作树是把当前分支检出到工作空间后形成的 目录树,一般的开发工作都会基于工作树进行
索引index文件是对工作树进行代码修改后, 通过add命令更新索引文件;GIT系统通过 索引index文件生成tree对象
git revert 和 git reset的区别
git revert是用一次新的commit来回滚之前的 commit,此次提交之前的commit都会被保留
git reset是回到某次提交,提交及之前的commit 都会被保留,此commit id之后的修改都会被删除
配置不需要提交的文件
利用命令touch .gitignore新建文件
vim .gitignore//添加需要忽略哪些文件 夹下的什么类型的文件
提交时发生冲突如何解决
先在IDE里面对比本地文件和远程分支的文件; 然后把远程分支上文件的内容手工修改到本地文件; 然后再提交冲突的文件使其保证与远程分支的文件一致; 然后再提交自己修改的部分。
通过git stash命令,把工作区的修改提交到栈区,目的是保存工作区的修改; 通过git pull命令,拉取远程分支上的代码并合并到本地分支,目的是消除冲突; 通过git stash pop命令,把保存在栈区的修改部分合并到最新的工作空间中;
解释 Forking 工作流程的优点
不是用单个服务端仓库充当“中央”代码库, 而是为每个开发者提供自己的服务端仓库; 因此Forking 工作流程常用于开源项目中
主要优点是可以汇集提交贡献,又无需每个开发者提交到 一个中央仓库中,从而实现干净的项目历史记录。
开发者先将提交推送到自己的公共仓库中; 然后向主仓库提交请求拉取(pull request); 由项目维护人员集成更新
Gitflow 工作流程
Gitflow 工作流程使用两个并行的、 长期运行的分支来记录项目的历史记录, 分别是master和develop分支
Master是准备发布线上版本的分支, 内 容是经过全面测试和核准的(生产就绪)
Hotfix,维护(maintenance) 或修复(hotfix)分支是用于给快 速给生产版本修复打补丁的
Develop是合并所有功能(feature)分支, 并执行所有测试的分支;当内容经过彻底检 查和修复后,才能合并到master分支
Feature是具体功能开发的小分支
正则表达式在java中的应用
java的split()
. 、 | 和 * 等转义字符,必须得加 \\
多个分隔符,可以用 | 作为连字符
正则表达式匹配ip地址
IP地址的长度为32位(共有2^32个IP地址), 分为4段,每段8位,用十进制数字表示, 每段数字范围为0~255,段与段之间用句点隔开
根据规则:每段相同,范围都在 0 ~ 255 0~255 对应的正则表达式为 ` 2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2} `
知识点
元字符
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束
字符转义
. 、 | 和 * 等转义字符,必须得加 \\
重复
*重复零次或更多次
+重复一次或更多次
?重复零次或一次
{n}重复n次
{n,}重复n次或更多次
{n,m}重复n到m次
分组(以(\d{1,3}\.){3}\d{1,3}为例)
要理解这个表达式,请按下列顺序分析它
\d{1,3}匹配1到3位的数字
(\d{1,3}\.){3}匹配三位数字加上一个 英文句号(这个整体也就是这个分组)重复3次
最后再加上一个一到三位的数字(\d{1,3})
登录方式
多点登录
单点登录
cdn(内容分发网络)
CDN节点解决了跨运营商和跨地域访问的问题,访问延时大大降低
CDN起到了分流作用,减轻了源站的负载
集群间Session 共享问题解决方案

1. nginx配置ip_hash为负载均衡策略即可解决session共享问题

优缺点
优点

缺点

nginx配置实例

2. 服务器之间session复制(tomcat)

优缺点
优点

缺点

tomcat的配置步骤

3. session统一缓存
maven
依赖jar包时版本冲突的解决
常用maven命令
mvn clean:清理
mvn compile:编译主程序
mvn test-compile:编译测试程序
mvn test:执行测试
mvn package:打包
mvn install:安装
maven中pom的标签说明

依赖的基本坐标

类型和排除依赖等

maven实现环境配置的隔离
pom文件中编写环境的配置

properties中读取pom标签中的配置

注意:要从properties中读取文件的配置成功

maven项目的包结构

maven私服
短信登录API
短信验证码有效期30分钟
验证码为4位纯数字
每个手机号60秒内只能发送一次短信验证码,且这一规则的校验必须在服务器端执行
同一个手机号在同一时间内可以有多个有效的短信验证码
保存于服务器端的验证码,至多可被使用3次(无论和请求中的验证码是否匹配),随后立即作废,以防止暴力攻击
短信验证码不可直接记录到日志文件
发送短信验证码之前,先验证图形验证码是否正确(可选)
集成第三方API做登录保护(可选)
HTTP数据量很大,怎么发送
使用post方法
使用多线程
JAVA实现定时任务的几种方式
JDK 自带的定时器Timer实现
Quartz 定时器实现
Spring 定时任务
开发中使用的工具
Java 线上诊断工具 Arthas
IDE 插件 Cloud Toolkit
混沌实验注入工具 ChaosBlade
Java 代码规约扫描插件
应用实时监控工具 ARMS
静态开源站点搭建工具 Docsite
性能测试工具 PTS
数据处理工具 EasyExcel