JVM中有哪些引用?
强引用:new的对象。哪怕内存溢出也不会回收
软引用:只有内存不足时才会回收
弱引用:每次垃圾回收都会回收
虚引用:必须配合引用队列使用,一般用于追踪垃圾回收动作
limit 过大如何优化
正常情况limit是把所有的数据拿去来,然后再去回表,在丢掉前面的一大部分数据,在返回
SELECT * FROM xxx WHERE
ID > =(select id from xxx limit 1000000, 1)
limit 20;
SELECT * FROM xxx a
JOIN (select id from xxx limit 1000000, 20) b
ON a.ID = b.id;
MySQL如何做慢SQL优化
可以查看执行计划分析数据的扫描类型、索引是否生效,常见的慢查询优化有:
(1)尽量减少select的数据列,尽量使用覆盖索引
(2)orderby查找时使用索引进行排序,否则的话需要进行回表
(3)groupby查询时,同样要用索引,避免使用到临时表
(4)使用count函数时直接使用count的话count()的效率最高。count()或count(唯一索引)或count(数字):表中总记录数,count(字段)不会统计null
(5)分页查询时,如果limit 后面的数字太大,再limit主键后n条数据就能走覆盖索引, 可以使用子查询查出主键
(6) 使用复杂查询时,使用关联查询来代替子查询,并且最好使用内连接
(7) 在写update语句时,where条件要使用索引,否则会锁会从行锁升级为表锁
(8)表中数据是否太大,是不是要分库分表
COUNT(1)、COUNT(*)与COUNT(字段)哪个更快?
COUNT()MySQL 对count()进行了优化,count(*)直接扫描主键索引记录,并不会把全部字段取出来,直接按行累加。
COUNT(1)InnoDB引擎遍历整张表,但不取值,server 层对于返回的每一行,放一个数字“1”进去,按行累加。
COUNT(字段)如果这个“字段”是定义为NOT NULL,那么InnoDB 引擎会一行行地从记录里面读出这个字段,server 层判断不能为NULL,按行累加;如果这个“字段”定义允许为NULL,那么InnoDB
引擎会一行行地从记录里面读出这个字段,然后把值取出来再判断一下,不是 NULL才累加。
所以count(字段)慢就慢在计算字段不为NULL的情况
实验结果
1.从上面的实验我们可以得出,COUNT(*)和COUNT(1)是最快的,其次是COUNT(id)。
2.count(*)被MySQL查询优化器改写成了count(0),并选择了idx_salary索引。
3.count(1)和count(id)都选择了idx_salary索引。
InnoDB和MySAM的 count(*)效率上也有很多差别,因为InnoDB事务操作可能会通过拿到行级锁,在进行统计,所以要把MySAM的count要慢。
哪些情况索引会失效
(1)违背最左匹配原则,索引失效
(2)where条件中有or,除非所有查询条件都有索引,否则失效
(3)like查询用%开头,索引失效
(4)索引字段发生类型转换,索引失效
(5)索引列参与计算,索引失效
(6)mysql觉得全表扫描更快时(数据少),索引失效
执行计划中有哪些字段?
我们想看一个sql的执行计划使用的语句是explain+SQL,表中的字段包括:
type:扫描类型,效率从底到高为ALL(全表扫描)>index(全索引扫描,我们的需要的数据在索引中可以获取)>range(使用索引进行范围查找)>ref(使用非唯一索引列进行了关联查询)> eq_ref (使用唯一索引进行关联查询)>const(使用唯一索引查询一行数据)>system(表中只有一行数据)
index:表示使用覆盖索引
rows:找到了多少行数据
key:实际使用到的索引
possible_keys(可能的):当前查询语句可能用到的索引,
可能为null(如果用了索引但是为null有可能是表数据太少innodb认为全表扫描更快)
MySQL有哪些锁
基于粒度:
*表级锁:对整张表加锁,粒度大并发小
*行级锁:对行加锁,粒度小并发大
*间隙锁:间隙锁,锁住表的一个区间,间隙锁之间不会冲突只在可重复读下才生效,解决了幻读
基于属性:
*共享锁:又称读锁,一个事务为表加了读锁,其它事务只能加读锁,不能加写锁
*排他锁:又称写锁,一个事务加写锁之后,其他事务不能再加任何锁,避免脏读问题
ClassLoader的子类
● 重写loadClass()方法
● 重写findClass()方法 打破双亲委派模型,那么只需要重写findClass方法即可
在打破双亲委派模型的情况下,一般是重写 findClass 方法而不是 loadClass 方法。
这是因为 loadClass 方法中通常包含了双亲委派的逻辑,
而findClass 方法是在双亲委派无法完成加载时由子类加载器自己实现的方法。
有哪些异常:
RejectedExecutionException:拒绝执行异常
描述:当线程池已关闭或线程池和工作队列都已满时,尝试提交新任务将抛出此异常。
解决方案:可以考虑调整线程池的大小或队列长度,或者更改拒绝策略来处理这种情况。
OutOfMemoryError:内存溢出
描述:如果线程池中的线程数或队列大小配置得太大,或者任务创建了太多大对象,你可能会遇到内存溢出错误。
解决方案:优化代码以减少内存使用,或增加JVM的最大堆大小。
NullPointerException:空指针
描述:当尝试提交的任务为null时,将抛出此异常。
解决方案:确保提交到线程池的任务不是null。
IllegalStateException:不正确状态
描述:当线程池处于不正确的状态时(例如,尝试多次关闭线程池),可能会抛出此异常。
解决方案:检查代码以确保线程池的正确使用。
RuntimeException 或 ExecutionException:
描述:当任务抛出运行时异常时,如果你使用了 Future.get() 方法来获取结果,将包装为 ExecutionException 抛出。
解决方案:捕获这些异常并适当处理
进程和线程的区别,进程间如何通信
进程:系统运行的基本单位,进程在运行过程中都是相互独立,但是线程之间运行可以相互影响。
线程:独立运行的最小单位,一个进程包含多个线程且它们共享同一进程内的系统资源
进程间通过管道、 共享内存、信号量机制、消息队列通信
Thread.yield()的作用
Thread.yield():
一定是当前线程调用此方法,当前线程放弃获取CPU的时间片,由运行态转变为就绪态,
让操作系统中再次选择线程执行。
作用:让相同优先级的线程轮流执行,但并不能保证轮流执行,根据解释我们了解到,
转成就绪态的的线程还有可能再次选中执行。Thread.yield()方法不会导致阻塞。
Thread.yield不会释放锁。那会不会出现死锁的情况?
比如线程1拿到锁,线程2等待,现在线程1执行Thread.yield()让出cpu执行权,
但是线程2因为没有锁,还是会阻塞,就算给线程2执行权,因为没有锁,还是阻塞。
脏读、重复读、幻读解决原理
读已提交RC:解决了脏读的问题,使用的是MVCC
重复读RR:解决重复读的问题,InnoDB也解决了幻读的问题
不可重复读如何解决:MVCC和行级锁
幻读的解决:间隙锁(Gap Lock)+ 防止全表扫
InnoDB通过间隙锁和防止全表扫描两种机制来避免幻读的问题。间隙锁可以防止其他事务在特定范围内插入新记录,而防止全表扫描则可以减少其他事务对整个表的读取和修改操作。
left join和inner join的区别
1.返回不同
innerjoin只返回两个表中联结字段相等的行。left join返回包括左表中的所有记录和右表中联结字段相等的记录。
2.数量不同
inner join的数量小于等于左表和右表中的记录数量。left join的数量以左表中的记录数量相同。
3.记录属性不同
inner join不足的记录属性会被直接舍弃。left join不足的记录属性用NULL填充。
执行计划
查看执行计划:
explain:
索引列:possible_keys -可能用到的,key-实际用到的
限流数量评估
1、限流的评估:第一个是对哪个接口限流,这个接口是查询操作,还是事务操作,然后再基于下面的条件进行帅选。下面数据也可以通过压测来看看接口的最大能有多大
1、QPS(每秒请求数)限流: 设定一个阈值,超过这个阈值的请求数将被限制。具体的阈值应该根据你的应用程
序的性能和容量来确定。逐步增加限流阈值,然后观察系统的响应能力,以找到最适合你应用程序的值。
2、TPS限流: 控制同时允许的并发连接数。这可以帮助防止由于大量同时连接而导致的系统过载。
2、第二个考虑的点是,是否要排队或者等待。超过了怎么办,进到阻塞队列还是消息里面去?
排队和等待
当达到限流阈值时,可以选择将请求放入队列并逐渐处理,而不是直接拒绝请求。这样可以避免突然的拒绝服务,
但可能会导致延迟增加。
3、第三个点:
监控和日志: 实时监控系统的性能指标,并记录限流事件和相关的日志,以便后续分析和调整限流策略。
什么是分布式存储
分布式存储技术是一种概念,其实就是通过集群部署,提高可用和负载均衡。比如主从复制,或者分片,像redis和mysql都可以分布式存储。
Java线程通信方式有哪些?
1、共享变量:多个线程共享同一个变量,通过该变量进行通信。需要确保对共享变量的访问是原子的,可以通过synchronized关键字或java.util.concurrent包中的锁机制来实现。
2、等待和通知机制(Wait and Notify):使用Object类的wait()、notify()和notifyAll()方法,线程可以等待某个条件满足后被唤醒。
3、使用Lock和Condition:使用java.util.concurrent.locks包中的Lock和Condition来实现更灵活的线程通信。
4、信号量:信号量是一种常见的线程同步机制,可用于控制多个线程对共享资源的访问。Java 提供了 Semaphore 类来实现信号量,Semaphore 类有两个常用的方法 acquire() 和 release(),分别用于获取和释放信号量。
5、消息队列通信:
6、管道:管道是一种用于线程间通信的高级机制,它可以实现一个线程向另一个线程传送数据。Java 提供了 PipedInputStream 和 PipedOutputStream 两个类来支持管道的实现,其中 PipedInputStream 用于读取数据,PipedOutputStream 用于写入数据。
为什么Zookeeper不适合存储大量数据呀
- 设计方面:ZooKeeper需要把所有的数据(它的data tree)加载到内存中。这就决定了ZooKeeper存储的数据量受内存的限制。
- 工程方面:ZooKeeper的设计目标是为协同服务提供数据存储,数据的高可用性和性能是最重要的系统指标,处理大数量不是ZooKeeper的首要目标。因此,ZooKeeper不会对大数量存储做太多工程上的优化。