String 由 char[] 数组构成,使用了 final 修饰,是不可变对象,可以理解为常量,线程安全;对 String 进行改变时每次都会新生成一个 String 对象,然后把指针指向新的引用对象。
Thread.sleep(long time)
Java 对象实现序列化要实现 Serializable 接口。
public class Singleton { private static volatile Singleton instance = null; private Singleton(){} public static Singleton getInstance(){ if (null == instance) { synchronized (Singleton.class) { if (null == instance) { instance = new Singleton(); } } } return instance; } }
一个新的线程被创建,还没开始运行。
一个线程准备就绪,随时可以运行的时候就进入了 Runnable 状态。
Runnable 状态可以是实际正在运行的线程,也可以是随时可以运行的线程。
多线程环境下,每个线程都会被分配一个固定长度的 CPU 计算时间,每个线程运行一会儿就会停止让其他线程运行,这样才能让每个线程公平的运行。这些等待 CPU 和正在运行的线程就处于 Runnable 状态。
例如一个线程在等待 I/O 资源,或者它要访问的被保护代码已经被其他线程锁住了,那么它就在阻塞 Blocked 状态,这个线程所需的资源到位后就转入 Runnable 状态。
如果一个线程在等待其他线程的唤醒,那么它就处于 Waiting 状态。以下方法会让线程进入等待状态:
无需等待被其他线程显示唤醒,在一定时间后有系统自动唤醒。
以下方法会让线程进入有限等待状态:
一个线程正常执行完毕,或者意外失败,那么就结束了。
void Runnable.run()
V Callable.call() throws Exception
Callable
Future<T> submit(Callable<T> task)
Runnable
void execute(Runnable command)
如果一个操作 happens-before 另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前。
corePoolSize -> 任务队列 -> maximumPoolSize -> 拒绝策略
>
核心线程在线程池中一直存活,当有任务需要执行时,直接使用核心线程执行任务。当任务数量大于核心线程数时,加入等待队列。当任务队列数量达到队列最大长度时,继续创建线程,最多达到最大线程数。当设置回收时间时,核心线程以外的空闲线程会被回收。如果达到了最大线程数还不能够满足任务执行需求,则根据拒绝策略做拒绝处理。
|:---|:---| | AbortPolicy | 抛出 RejectedExecutionException | | DiscardPolicy | 什么也不做,直接忽略 | | DiscardOldestPolicy | 丢弃执行队列中最老的任务,尝试为当前提交的任务腾出位置 | | CallerRunsPolicy | 直接由提交任务者执行这个任务 |
Runtime.getRuntime().availableProcessors()
双亲委派模式 当一个类需要加载时,判断当前类是否被加载过。已经被加载的类会直接返回,否则才会尝试加载。加载的时候,首先会把该请求委派该父类加载器的 loadClass() 处理,因此所有的请求最终都应该传送到顶层的启动类加载器 BootstrapClassLoader 中。当父类加载器无法处理时,才由自己来处理。当父类加载器为 null 时,会使用启动类加载器 BootstrapClassLoader 作为父类加载器。
双亲委派模式
当一个类需要加载时,判断当前类是否被加载过。已经被加载的类会直接返回,否则才会尝试加载。加载的时候,首先会把该请求委派该父类加载器的 loadClass() 处理,因此所有的请求最终都应该传送到顶层的启动类加载器 BootstrapClassLoader 中。当父类加载器无法处理时,才由自己来处理。当父类加载器为 null 时,会使用启动类加载器 BootstrapClassLoader 作为父类加载器。
loadClass()
BootstrapClassLoader
CMS
G1
在 Java 语言中,可作为 GC Roots 的对象包括 4 种情况: a) 虚拟机栈中引用的对象(栈帧中的本地变量表); b) 方法区中类静态属性引用的对象; c) 方法区中常量引用的对象; d) 本地方法栈中 Native 方法引用的对象。
在 Java 语言中,可作为 GC Roots 的对象包括 4 种情况:
a) 虚拟机栈中引用的对象(栈帧中的本地变量表); b) 方法区中类静态属性引用的对象; c) 方法区中常量引用的对象; d) 本地方法栈中 Native 方法引用的对象。
索引很大,通常作为文件存储在磁盘上面,每次检索索引都需要把索引文件加载进内存,所以磁盘 IO 的次数是衡量索引数据结构好坏的重要指标。应用程序在从磁盘读取数据时,不只是读取需要的数据,还会连同其他数据以页的形式做预读来减少磁盘 IO 的次数。数据库的设计者将每个节点的大小设置为一页的大小,同时每次新建节点时都重新申请一个页,这样检索一个节点只需要一次 IO,根据索引定位到数据只需要 h- 1(h 为 B 树高度,根节点常驻内存) 次 IO,而 d (度,可以理解为宽度)与 h 称反比,即 d 越大,高度就越小,所以树越扁,磁盘 IO 次数越少,即渐进复杂度为 logdN ,这也是为什么不选择红黑树做索引的原因。前面可以得出结论,d 越大,索引的性能越好。节点由 key 和 data 组成,页的大小一定,key 和 data 越小,d 越大。B + 树去掉了节点内的 data 域,所以有更大的 d , 性能更好。
在 MySQL 中,可以指定多个列为索引,即联合索引。比如 index(name,age) ,最左前缀原则是指查询时精确匹配到从最左边开始的一列或几列(name;name&age),就可以命中索引。如果所有列都用到了,顺序不同,查询引擎会自动优化为匹配联合索引的顺序,这样是能够命中索引的。
(1) 定义有主键的列一定要建立索引。因为主键可以加速定位到表中的某行
(2) 定义有外键的列一定要建立索引。外键列通常用于表与表之间的连接,在其上创建索引可以加快表间的连接
(3) 对于经常查询的数据列最好建立索引。
① 对于需要在指定范围内快速或频繁查询的数据列,因为索引已经排序,其指定的范围是连续的,查询可以利用索引的排序,加快查询的时间
② 经常用在 where 子句中的数据列,将索引建立在 where 子句的集合过程中,对于需要加速或频繁检索的数据列,可以让这些经常参与查询的数据列按照索引的排序进行查询,加快查询的时间。
where
Inno DB 默认隔离级别为可重复读级别,分为快照度和当前读,并且通过行锁和间隙锁解决了幻读问题。
在 InnoDB 中为每行增加两个隐藏的字段,分别是该行数据 创建时的版本号 和 删除时的版本号 ,这里的版本号是系统版本号(可以简单理解为事务的 ID),每开始一个新的事务,系统版本号就自动递增,作为事务的 ID 。通常这两个版本号分别叫做创建时间和删除时间。
详细参考:《 脏读、幻读和不可重复读》
|:---|:---| | 类别 | 说明 | |singleton| 默认在 Spring 容器中仅存在一个实例 | |prototype| 每次调用 getBean() 都重新生成一个实例 | |request| 为每个 HTTP 请求生成一个实例 | |session| 同一个 HTTP session 使用一个实例,不同 session 使用不同实例 |
简单来说四步:
在这四步的基础上面,Spring 提供了一些拓展点:
实现方式两种:
默认 PROPAGATION_REQUIRED ,如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。
TCP 流量控制,主要使用 滑动窗口协议 ,滑动窗口是接受数据端使用的窗口大小,用来告诉发送端接收端的缓存大小,以此可以控制发送端发送数据的大小,从而达到流量控制的目的。这个窗口大小就是我们一次传输几个数据。对所有数据帧按顺序赋予编号,发送方在发送过程中始终保持着一个发送窗口,只有落在发送窗口内的帧才允许被发送;同时接收方也维持着一个接收窗口,只有落在接收窗口内的帧才允许接收。
削峰填谷,异步解耦 。
这个问题可以换个思路,保证消息重复消费,其实是保证程序的幂等性。无论消息如何重复,程序运行的结果是一致的。比如消费消息后做数据库插入操作,为了防止消息重复消费,可以在插入前先查询一下有没有对应的数据。
消费端在接收到消息后放入内存队列,然后对队列中的消息进行有序消费。
消息过期失效问题,如果消息一段时间不消费,导致过期失效了,消息就丢失了,只能重新查出丢失的消息,重新发送。 再来说消息积压的问题:(思路是快速消费掉积压的消息)
消息队列满了:只能边接收边丢弃,然后重新补回丢失的消息,再做消费。
kafka 为例:
常用命令: set,get,decr,incr,mget 等。
常用命令: hget,hset,hgetall 等
常用命令: lpush,rpush,lpop,rpop,lrange 等
可以通过 lrange 命令,就是从某个元素开始读取多少个元素,可以基于 list 实现分页查询。
常用命令: sadd,spop,smembers,sunion 等
常用命令: zadd,zrange,zrem,zcard 等
定期删除和惰性删除的形式。
数据快照(RDB)+ 修改数据语句文件(AOF)
缓存雪崩 缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。
缓存穿透 一般是黑客故意去请求缓存中不存在的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。
Redis 实现消息队列依赖于 Redis 集群的稳定性,通常不建议使用。
Nginx 是一款轻量级的 Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。 Nginx 主要提供反向代 理、负载均衡、动静分离(静态资源服务)等服务。
将请求分摊到多台机器上去,高并发,增加吞吐量。
动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来,动静资源做好了拆分以后,我们就可以根据静态资源的特点将其做缓存操作,这就是网站静态化处理的核心思路。
Java 八股文介绍到这里,更多java学习请参考编程字典java教程 和问答部分,谢谢大家对编程字典的支持。
原文链接:https://blog.csdn.net/qq_23696693/article/details/108406217?ops_request_misc=&request_id=&biz_id=102&utm_term=java&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~sobaiduweb~default-9-108406217.nonecase&spm=1018.2226.3001.4450