java 面试问的问题和个人理解(三年)(一)

我在昨天在QQ群里看到了一个三年 Java程序员 分享的面试题,我当时只是单纯想复制出来等到下班看看。但是在看这些问题的时候,让我想到了一位大神之前在csdn上在2017年6月左右分享的java 面试需要会的点。这样,我昨天把这些问题回顾了一下,在这里希望分享出来,大家一起聊聊技术。

开始:

首先是QQ群上看到的知识点

比如事物的隔离级别的问题,线程池种类及应用场景和优缺点,如何监控一台服务器的负载CPU、内存、IO,如何定位OOM产生原因,Redis怎么解决缓存击穿、Spring Boot,Dubbo,hash算法怎么实现的,ip过滤怎么做,BTree的实现原理,MySQL的引擎有哪些及区别,volitale的线程安全


一.事物的隔离级别

隔离性分为四个级别:
1读未提交:(Read Uncommitted)
2读已提交(Read Committed) 大多数数据库默认的隔离级别
3可重复读(Repeatable-Read) mysql数据库所默认的级别
4序列化(serializable)


在一个进程的事务当中,我更改了其中的一行数据,但是我修改完之后就释放了锁,这时候另一个进程读取了该数据,此时先前的事务是还未提交的,直到我回滚了数据,另一个进程读的数据就变成了无用的或者是错误的数据。我们通常把这种数据叫做脏数据,这种情况读出来的数据叫做賍读。


怎么办?依然是靠锁机制。无非是锁的位置不同而已,之前是只要操作完该数据就立马释放掉锁,现在是把释放锁的位置调整到事务提交之后,此时在事务提交前,其他进程是无法对该行数据进行读取的,包括任何操作。那么数据库为此种状态的数据库操作规则又给了一个名字叫做:读已提交(Read Committed),或者也可以叫不可重复读。这也就是事务的第二个隔离性。


在某些情况下,不可重复读并不是问题,比如我们多次查询某个数据当然以最后查询得到的结果为主。但在另一些情况下就有可能发生问题,例如对于同一个数据A和B依次查询就可能不同,A和B就可能打起来了……

继续看下面的测试结果:


1)把隔离性调为READ-COMMITTED(读取提交内容)设置A的事务隔离级别,并进入事务做一次查询
<img src="https://i-blog.csdnimg.cn/blog_migrate/ae8a594ba9b5254d48c141addb5ee399.jpeg" class="content_image">
2)B开始事务,并对记录进行修改
<img src="https://i-blog.csdnimg.cn/blog_migrate/a6a32f88a766de648afafc25cd825f41.jpeg" class="content_image">
3)A再对user表进行查询,发现记录没有受到影响
<img src="https://i-blog.csdnimg.cn/blog_migrate/22b41f330ed891d9be25cc58867c0cfb.jpeg" class="content_image">
4)B提交事务
<img src="https://i-blog.csdnimg.cn/blog_migrate/7b704b04a8d241d6c7a146c7753e9495.jpeg" class="content_image">
5)A再对user表查询,发现记录被修改
<img src="https://i-blog.csdnimg.cn/blog_migrate/d583746823bf138e1e4d0397e23245c3.jpeg" class="content_image">

试验进行到这里,你会发现,在同一个事务中如果两次读取相同的数据时,最后的结果却不一致。这里我们把这种现象称为:不可重复读。因为在第一个事务读取了数据之后,此时另一个事务把该数据给修改了,这时候事务提交,那么另一个事务在第二次读取的时候,结果就不一样,一个修改前的,一个是修改后的。

但是细心的你会发现,既然你说此种隔离性是在事务提交后才释放锁,那么在试验过程中,在该数据未提交前,另一个事务为什么也是仍然可以读取的呀。是我说错了吗?不是的,在这里mysql使用了一个并发版本控制机制,他们把它叫做MVCC,通俗的也就是说:mysql为了提高系统的并发量,在事务未提交前,虽然事务内操作的数据是锁定状态,但是另一个事务仍然可以读取,大多数数据库默认的就是这个级别的隔离性。但mysql不是。

而且不只是在更新数据时出现这个问题,在插入数据时仍然会造成类似的这样一种现象:mysql虽然锁住了正在操作的数据行,但它仍然不会阻止另一个事务往表插入新行新的数据。比如:一个事务读取或更新了表里的所有行,接者又有另一个事务往该表里插入一个新行,在事务提交后。原来读取或更改过数据的事务又第二次读取了相同的数据,这时候这个事务中两次读取的结果集行数就不一样。原来更新了所有行,而现在读出来发现竟然还有一行没有更新。这就是所谓的幻读。

为了防止同事务中两次读取数据不一致,(包括不可重读和幻读),接下来该如何继续做呢?!

mysql依然采取的是MVCC并发版本控制来解决这个问题。具体是:如果事务中存在多次读取同样的数据,MySQL第一次读的时候仍然会保持选择读最新提交事务的数据,当第一次之后,之后再读时,mysql会取第一次读取的数据作为结果。这样就保证了同一个事务多次读取数据时数据的一致性。这时候,mysql把这种解决方案叫做:可重复度(Repeatable-Read),也就是上述所写的第三个隔离性,也是mysql默认的隔离级别。

注意:幻读和不可重复读(Read Committed)都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。

说到这里,真的就完事了吗?到这里其实mysql并未完全解决数据的一致性问题。只是在读取上做了手脚,解决了传统意义上的幻读和不可重复读。
例子:1 A事务开启,B事务开启。
2 B事务往表里面插入了一条数据,但还并未提交。
3 A事务开始查询了,并没有发现B事务这次插入的数据。然后此时B事务提交了数据。
4 于是乎,A事务就以为没有这条数据,就开始添加这条数据,但是却发现,发生了数据 重复冲突。


最后这个时候,该我们的最后一种隔离级别也是最高的隔离级:别序列化(serializable)登场了。
该隔离级别会自动在锁住你要操作的整个表的数据,如果另一个进程事务想要操作表里的任何数据就需要等待获得锁的进程操作完成释放锁。可避免脏读、不可重复读、幻读的发生。当然性能会下降很多,会导致很多的进程相互排队竞争锁。

后记:以上所说的四种隔离性的锁机制应用是数据库自动完成的,不需要人为干预。隔离级别的设置只对当前链接有效。对于使用MySQL命令窗口而言,一个窗口就相当于一个链接,当前窗口设置的隔离级别只对当前窗口中的事务有效


二.线程池种类及应用场景和优缺点

这个之后再说

三、如何监控一台服务器的负载CPU、内存、IO

四。Redis怎么解决缓存击穿

我们在用缓存的时候,不管是Redis或者Memcached,基本上会通用遇到以下三个问题:

  • 缓存穿透
  • 缓存并发
  • 缓存失效
  • 缓存雪崩

我们在项目中使用缓存通常都是先检查缓存中是否存在,如果存在直接返回缓存内容,如果不存在就直接查询数据库然后再缓存查询结果返回。这个时候如果我们查询的某一个数据在缓存中一直不存在,就会造成每一次请求都查询DB,这样缓存就失去了意义,在流量大时,可能DB就挂掉了。

那这种问题有什么好办法解决呢?

要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。
有一个比较巧妙的作法是,可以将这个不存在的key预先设定一个值。
比如,"key" , “&&”。
在返回这个&&值的时候,我们的应用就可以认为这是不存在的key,那我们的应用就可以决定是否继续等待继续访问,还是放弃掉这次操作。如果继续等待访问,过一个时间轮询点后,再次请求这个key,如果取到的值不再是&&,则可以认为这时候key有值了,从而避免了透传到数据库,从而把大量的类似请求挡在了缓存之中。这是缓存穿透

缓存击穿:简单点来说就是在同一个过期时间,在这个时间,对DB的压力会很大,

解决办法:加互斥锁,如果没查到,先往里面设置一个标志,设置成功了,再去db查询,redis.setnx(key_mutex, 13 * 60) == 1

三、缓存失效

引起这个问题的主要原因还是高并发的时候,平时我们设定一个缓存的过期时间时,可能有一些会设置1分钟啊,5分钟这些,并发很高时可能会出在某一个时间同时生成了很多的缓存,并且过期时间都一样,这个时候就可能引发一当过期时间到后,这些缓存同时失效,请求全部转发到DB,DB可能会压力过重。

那如何解决这些问题呢?
其中的一个简单方案就时讲缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。




java 面试问的问题和个人理解(三年)(一)就到这里,这个里面我有自己的理解,但是我文采不行,还是扒人家的了,后面是转载链接,明天写java 面试问的问题和个人理解(三年)(二) ,用自己话,但是可能文采不行,多担待


作者:沈杰
链接:https://www.zhihu.com/question/30272728/answer/132403859
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孔明兴汉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值