Java常考面试题(四)

一、什么是死锁(deadlock)?

      自我解答:

            这个问题,依稀在讲解数据库时有学习过。不过忘记的差不多了,大概就是A有一把锁,B也有一把锁,现在A获得了B这把锁,此时,A失去CPU,B又获得了A这吧锁,此时就造成了死锁,因为双方都解不开了。

      参考答案:

            两个线程或两个以上线程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁。结果就是这些线程都陷入了无限的等待中。

 

      自我评价:

            顺便把其他情况也复习一下,感觉这个需要理解,自己对这个概念也有点模糊不清。

            1、死锁:A等待B、B等待A,造成死锁,无限的等待中,

            2、死锁的问题我就想到了复习一下数据库的事务的特性和隔离级别吧

                什么是事务?一组业务逻辑,注意,是一组。例如,A转钱给B A就要有更新语句,B也要有更新语句,这两个一起才是一个事务。

              事务的特性:ACID

                A:原子性,就是事务不可被划分,是一个整体,要么一起成功,要么就一起失败

                C:一致性:银行转账,A转走100块给B,A减少100,那么B就增加100

                I:隔离性:比较麻烦的点,多个事务对同一个内容的并发操作

                D:持久性:已经提交的事务,就已经保存到数据库中,不能再更改了。

              事务隔离性产生的问题

                1、脏读:事务 读取到了 另一个事务还未提交的数据。

                   例如:小明去银行取钱,读取到卡里有100元,然后小明将100元取出,但是数据还没有提交到数据库中;          这个时候小红拿着同一张卡去取钱,因为小明的取出的100元还没有被写到数据库,小红读到的还是100            元,小红读到的就是小明没有提交的数据,这就是脏读。

                2、不可重复读: 事务 读取到了 另一个事务已经提交的数据。 针对update

                   有些人会问,这不是问题,正确的做法不就是要读取到已经提交的数据吗,但有些情况是只需要读取未提交的数据,所以这是个问题。

                    例如:由于经验少,目前没有遇到这种情况,但是肯定有,

                3、虚度、幻读:事务 读取到了 另一个事务已经提交的数据。 针对的是insert delete

               

 

              解决事务隔离性产生的问题

                1、读未提交:解决O个问题,还有3个问题 这三个问题就是前面说的三个

                2、读已提交:解决1个问题,还有2个问题,解决第一个问题,还有后面两个问题

                3、可重复读:一个事务读到的还是原来的数据,即使另一个事务已经提交,解决2个问题,还有1个问题 解决前面两个问题,还有最后一个问题

                4、串行化:单事务、两个事务同时对一个内容进行操作,必须等待前一个事物操作完成,后一个事务才能进行操作。解决全部问题。

                

               mysql默认的隔离级别:可重复读。  oracle默认的隔离级别:读已提交

              

              丢失更新问题:

                   后一次更新将前一次更新的内容给覆盖了,这就是丢失更新问题,

                    l  A 查询数据,username = 'jack' ,password = '1234'l 

                       B 查询数据,username="jack", password="1234"l 

                     A 更新用户名 username="rose",password='1234'    -->   username="rose",password="1234"l 

                     B 更新密码   password="9999" ,username="jack"  -->   username="jack",password='9999'  

                  第三句话:A将用户名更新为rose  此时数据库 username = rose password = 1234

                  第四句话:B将密码改为9999 但用户名还是jack 但是更新后,又把原数据库中username的rose更新为jack了,密码为9999

 

              解决:乐观锁和悲观锁

                乐观锁:丢失更新肯定不会发生,在数据库中增加一个标识符,比较版本号,如果一样,修改版本自动+1.。如果不一样,必须先查询,再更新

                悲观锁:丢失更新肯定会发生:使用排他锁和共享锁

                      共享锁:只能读,不能写。

                      排他锁:只能一个进行写,不能拥有其他锁,也就是说,若事务T对数据对象A加上X锁,则只允许T读取和修改A,其他任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。这就保证了其他事务在T释放A上的锁之前不能再读取和修改A

 

  

二、如何确保N个线程可以访问N个资源同时又不导致死锁?

      自我解答:  

            这题不会

      参考答案:

            使用多线程的时候,一种非常简单的避免死锁的方式就是:指定获取锁的顺序,并强制线程按照指定的顺序获取锁。因此,如果所有的线程都是以同样的顺序加锁和释放锁,就不会出现死锁了。

      自我评价:

            首先得知道死锁的四个必要条件 

              (1) 互斥条件:一个资源每次只能被一个进程使用。
              (2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
              (3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
              (4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

                  解决死锁的方式最简单的就是让最后一个条件不成立,按同样的顺序加锁和释放锁

 

三、Java集合类框架的基本接口有哪些?

      自己解答:

            其实在写的随笔中,就有关于集合的总结,大概就三类接口、set、map、list

      参考答案:

           集合类接口指定了一组叫做元素的对象。集合类接口的每一种具体的实现类都可以选择以它自己的方式对元素进行保存和排序。有的集合类允许重复的键,有些不允许。
            Java集合类提供了一套设计良好的支持对一组对象进行操作的接口和类。Java集合类里面最基本的接口有:
            Collection:代表一组对象,每一个对象都是它的子元素。
            Set:不包含重复元素的Collection。
            List:有顺序的collection,并且可以包含重复元素。
            Map:可以把键(key)映射到值(value)的对象,键不能重复。 

 

       自我评价:

            1、set接口:不可重复,无序,实现类有HashSet、linkedset等。

            2、list接口:可重复,有顺序,实现类有arrayList、linkedList等

            3、map接口:以键值对的形式来存储数据,键不能重复,实现类有hashMap等,

              要看不同请看我写的JavaSE集合的深入的一系列博文

 

四、为什么集合类没有实现Cloneable和Serializable接口?

       自我解答:

           这个不知道,Serializable接口称为序列化接口,百度过,用来形成持久化对象用的,比如,将可序列化的对象存入到硬盘中。

 

      参考答案:

           克隆(cloning)或者是序列化(serialization)的语义和含义是跟具体的实现相关的。因此,应该由集合类的具体实现来决定如何被克隆或者是序列化

 

      自我评价:

           首先得明白Serializable接口干嘛用的

           1、Serializable接口

              将对象的状态保存在存储媒体中以便可以在以后重写创建出完全相同的副本;

              按值将对象从一个从一个应用程序域发向另一个应用程序域。

            上面的官方解释太难懂了,通俗的讲,就是将对象转换为字节流后,还能从字节流转换成原来的对象,需要实现这样的效果,就需要将对象类实现Serializable接口。

           2、cloning接口

              需要将对象克隆,也就是使用clone()方法时,就需要实现该接口

          明白了上面两个概念,实现着两个接口,是看具体的情况,并不是每个collection接口的实现类都需要使用上面的情况,所以只能根据具体的情况来决定是否实现Serializable接口和cloning接口。

 

      组织语言:    

            首先理解Serializable接口和cloning接口是干什么用的,Serializable接口是序列化接口,实现序列化接口的实现类就是使用字节流传输,而实现cloning接口,是能够克隆自己,使用clone()方法,而并不是所有的collection都需要用到上面两种情况,所以不需要在collection上实现着两个接口。

 

 

五、什么是迭代器(Iterator)?

      自己解答:

            迭代器,就是用来迭代各种数据类型的,比如,取出数组中的每个数据,取出集合中的每个数据,将不同存储数据的类型用一个统一的方法来迭代出数据,这就是迭代器,为什么需要迭代器,因为如果要取出数组中的数据和要取出集合中的数据,他们要执行的代码不一样, 不统一,所以就有了Iterator接口。就是为了解决这个问题。

    

      参考答案:

            Iterator接口提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返回迭代器实例的

            迭代方法。迭代器可以在迭代的过程中删除底层集合的元素,但是不可以直接调用集合的
            remove(Object Obj)删除,可以通过迭代器的remove()方法删除。

 

      自我评价:

            上面理解错了,使用iterator是因为在不同的集合中,都能使用Iterator来迭代,而不用管集合是哪个,而其他类也想用iterator迭代的话,那么就实现iterator接口,实现其中的方法,那么也能按照Iterator定义的方法来迭代了,平常普通数组就直接用for循环搞定啦,理解错了,是因为看一篇博客,讲解为什么有Iterator,迭代器设计模式时理解错了,博文地址:http://shmilyaw-hotmail-com.iteye.com/blog/1469288   感觉还不错这篇博客,起码让我知道了为什么使用Iterator,和它的设计。

           1、迭代器的使用

              实现了Iterator接口,使用方法iterator()要求容器返回一个Iterator,

                next():返回第一个元素

                hasNext():是否还有元素

                remove():将返回来的元素删除。

              注意:不可以直接调用集合中的方法remove()来删除元素,只能通过Iterator中的方法

            2、为什么要有迭代器?

              上面其实已经分析过来,为了让所有的集合都有统一的遍历方式,不用管集合是什么,迭代器统一了对容器的访问方式,collection接口就已经继承了Iterator接口,所以之下的所有collection接口实现类都已经实现了Iterator接口。

      

 

 

      

      

 

 

 

      

                 

posted @ 2016-11-14 21:12  有梦想的老王  阅读(1681)  评论(0编辑  收藏  举报