面经总结(六)

目录

1、Java IO 和 NIO的区别

2、一条SQL语句在MySQL中执行过程

3、mysql主库有更新但是从库还没有读取binlog,主库崩溃了从库无法保证一致性了怎么办?

4、web服务器的加载机制?

5、thread执行的run方法和start方法有什么不同?

6、线程间的通信方式

7、abc三个联合索引,条件为c=xx and a=xx,索引怎么走?

8、  Object有什么方法,什么时候用到hashcode方法

9、Java中有哪些集合,哪些是线程安全的.

10、ArrayList源码分析

11、LInkedArrayList

12、hashSet的实现

13、LinkedHashSet的实现

14、TreeSet的实现

15、LinkedHashMap的实现

16、介绍一下Java中的String,StringBuffer,StringBuilder

17、== 和equals()的区别

18、abstract 和final能同时使用吗

19、抽象类和接口的关系和区别

 20、Mybits中${}和#{}的区别


1、Java IO 和 NIO的区别

        IO是面向字节流的,NIO是面向缓冲区。IO是阻塞的,NIO是基于Selector的非阻塞。

        NIO的核心组件包括:Channel(通道),Buffer(缓冲区),Selector(选择器),其中Channel和Buffer比较好理解 。简单来说 NIO是面向通道和缓冲区的,意思就是:数据总是从通道中读到buffer缓冲区内,或者从buffer写入到通道中。

       Selector 一般称 为选择器 ,当然你也可以翻译为 多路复用器 。它是Java NIO核心组件中的一个,用于检查一个或多个NIO Channel(通道)的状态是否处于可读、可写。如此可以实现单线程管理多个channels,也就是可以管理多个网络链接。

        使用Selector的好处在于: 使用更少的线程来就可以来处理通道了, 相比使用多个线程,避免了线程上下文切换带来的开销。

面向流与面向缓冲

         Java IO和NIO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。 Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。

阻塞与非阻塞IO

        ava IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。 

2、一条SQL语句在MySQL中执行过程

  • MySQL 主要分为 Server 层和引擎层,Server 层主要包括连接器、查询缓存、分析器、优化器、执行器,同时还有一个日志模块(binlog),这个日志模块所有执行引擎都可以共用,redolog 只有 InnoDB 有。
  • SQL 等执行过程分为两类,一类对于查询等过程如下:权限校验—》查询缓存—》分析器—》优化器—》权限校验—》执行器—》引擎
  • 对于更新等语句执行流程如下:权限校验—》分析器----》权限校验----》执行器—》引擎—redo log prepare—》binlog—》redo log commit

3、mysql主库有更新但是从库还没有读取binlog,主库崩溃了从库无法保证一致性了怎么办?

        如果只是主库宕机,服务器还能起来还需要把主库的binlog拉下来,在从库补全把差距补回来。然后把这个从库作为主库。

4、web服务器的加载机制?

异步加载:异步加载也叫非阻塞模式加载,就是在浏览器在下载js时,同时还会执行后续的页面处理。异步加载的机制很常见。比如发布朋友圈时,你不用等所有文字和照片都上传完毕,才显示朋友圈,当你点击发送后,App上显示出你已发出的朋友圈,然而微信其实在后台仍然在上传数据,仔细看上图在发布完朋友圈之后,会有一次内容的闪屏,那个时候才是将数据正式发布并展示给好友。这样的异步处理减少了用户的等待时间,消除了用户的焦虑感。

延迟加载(lazy loading):顾名思义在需要的时候才加载,这样做效率会比较低,但是占用内存也低。页面有大量不同的模块组成,很多可能暂时不用或根本就没用到。就像图片的延迟加载,在图片出现在可视区域内时(在滚动条下拉)才加载显示图片。用户滚动到它们之前,视口外的图像不会加载。在某些情况下,它还可以帮助减少服务器负载。

预加载:预加载是一种浏览器机制,使用浏览器空闲时间来预先下载/加载用户接下来很可能会浏览的页面/资源,当用户访问某个预加载的链接时,如果从缓存命中,页面就得以快速呈现。

同步加载:一股脑把整个页面的内容全部加载给用户。网速不友好的情况下很容易就会“难产而死”。因此在加载过程中会出现白屏。

离线缓存加载:首先在有网时候把数据提前加载下来,缓存到本地,当没网的时候,直接加载已经缓存下来的内容。缓存的大小是有限的。

5、thread执行的run方法和start方法有什么不同?

        使用start方法才真正实现了多线程运行,因为这个时候不用等待我们的run方法执行完成就可以继续执行下面的代码。因为thread线程有5种状态,创建-就绪-运行-阻塞-死亡这五种,那么我们的start方法呢就是就绪这一步,因为这个时候我们的线程并没有立即的执行,而是得等待,等到我们的cpu有空闲的时候,才会执行线程里面的run方法,等run方法执行完了,线程就结束了。
        因为run方法是thread里面的一个普通的方法,所以我们直接调用run方法,这个时候它是会运行在我们的主线程中的,因为这个时候我们的程序中只有主线程一个线程,所以如果有两个线程,都是直接调用的run方法,那么他们的执行顺序一定是顺序执行,所以这样并没有做到多线程的这种目的。

6、线程间的通信方式

通过共享对象通信:线程间发送信号的一个简单方式是在共享对象的变量里设置信号值。线程A在一个同步块里设置boolean型成员变量hasDataToProcess为true,线程B也在同步块里读取hasDataToProcess这个成员变量。线程A和B必须获得指向一个MySignal共享实例的引用,以便进行通信。如果它们持有的引用指向不同的MySingal实例,那么彼此将不能检测到对方的信号。需要处理的数据可以存放在一个共享缓存区里,它和MySignal实例是分开存放的。

  • 管道输入/输出流,链接输入流和输出流
  • synchronized关键字
  • volatile关键字以及等待/通知(wait/notify)机制
  • ThreadLocal的子类InheritableThreadLocal可以取父线程中的值。
  • 参数传递,主线程向子线程传递參数,子线程向主线程传递参数都可以通过函数传递
  • 线程间通信的消息机制的Message和Handler

7、abc三个联合索引,条件为c=xx and a=xx,索引怎么走?

        只走a索引,在对sql语句进行分析和优化时,where后面的条件会重排序     

8、  Object有什么方法,什么时候用到hashcode方法

        hashCode,toString,getClass,notify,notifyAll,wait,equals.

        哈希码本身来说就是一种为了提高查找效率的一种算法,在hashSet,hashMap与hashTable中均用到了hashCode方法。

9、Java中有哪些集合,哪些是线程安全的.

        

         Collection和Map,是集合框架的根接口。

Collection的子接口:

  • Set:接口 ---实现类: HashSet、LinkedHashSet
  • Set的子接口SortedSet接口---实现类:TreeSet
  • List:接口---实现类: LinkedList,Vector,ArrayList

List集合

  • ArrayList:数组实现,查询快,增删慢,轻量级;(线程不安全)
  • LinkedList:双向链表实现,增删快,查询慢 (线程不安全)
  • Vector:数组实现,重量级 (线程安全、使用少)

Map接口

  • HashMap:键值对,key不能重复,但是value可以重复;key的实现就是HashSet;value对应着放;允许null的键或值;
  • Hashtable:线程安全的,不允许null的键或值;
  • Properties::key和value都是String类型,用来读配置文件;
  • TreeMap:对key排好序的Map; key 就是TreeSet, value对应每个key; key要实现Comparable接口或TreeMap有自己的构造器;
  • LinkedHashMap: 此实现与HashMap的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。存储的数据是有序的。

10、ArrayList源码分析

  • DEFAULT_CAPACITY:默认长度为10.
  • 底层是通过数组实现
  • arrayList中可以添加ull值
  • public ArrayList(Collection<? extends E> c),它可以在初始化时,接受所有的Collection的实现类
  • trimToSize()用于数组缩容,用来减小内存空间
  • arrayList每次扩容为原来的容量的1.5倍,扩容因子最适合范围为(1, 2),k=1.5时,就能充分利用前面已经释放的空间。如果k >= 2,新容量刚刚好永远大于过去所有废弃的数组容量。1.5 可以充分利用移位操作,减少浮点数或者运算时间和运算次数。

11、LInkedArrayList

  • 其底层采用的双向链表结构。
  •  ArrayList 一样,LinkedList 也支持空值和重复值。由于 LinkedList 基于链表实现,存储元素过程中,无需像 ArrayList 那样进行扩容。但有得必有失,LinkedList 存储元素的节点需要额外的空间存储前驱和后继的引用。另一方面,LinkedList 在链表头部和尾部插入效率比较高,但在指定位置进行插入时,效率一般。原因是,在指定位置插入需要定位到该位置处的节点,此操作的时间复杂度为O(N)。
  • ③ LinkedList 是非线程安全的集合类,并发环境下,多个线程同时操作 LinkedList,会引发不可预知的错误。
  • 每一个节点包含,pre,next和当前节点的值

12、hashSet的实现

        HashSet的实现是基于HashMap的,底层也是HashMap,存取的Value值都是同一个Object对象。

13、LinkedHashSet的实现

        LinkedHashSet的底层使用的是LinkedHashMap保证了数据存入和读取的一致性

14、TreeSet的实现

        TreeSet的底层是采用TreeMap实现的,底层为红黑树结构。TreeMap中存在Key的比较函数,通过比较key值将所有变量存入Key中。

15、LinkedHashMap的实现

        LinkedHashMap继承自HashMap,它的多种操作都是建立在HashMap操作的基础上的。同HashMap不同的是,LinkedHashMap维护了一个Entry的双向链表,保证了插入的Entry中的顺序。这也是Linked的含义。结构图如下:

    /**
     * LinkedHashMap中的node直接继承自HashMap中的Node。并且增加了双向的指针
     */
    static class Entry<K,V> extends HashMap.Node<K,V> {
        Entry<K,V> before, after;
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
    }

16、介绍一下Java中的String,StringBuffer,StringBuilder

         三者共同之处:都是final类,不允许被继承,主要是从性能和安全性上考虑的,因为这几个类都是经常被使用着,且考虑到防止其中的参数被参数修改影响到其他的应用。

        StringBuffer是线程安全,可以不需要额外的同步用于多线程中;StringBuilder是非同步,运行于多线程中就需要使用着单独同步处理,但是速度就比StringBuffer快多了;

         这三个类之间的区别主要是在两个方面,即运行速度和线程安全这两方面。

  • 首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > String

    • String最慢的原因:String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的
  • 在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的
  • 扩容为原来的2倍再加2,数组容量小于字符个数时进行扩容。

17、== 和equals()的区别

  • ==是直接比较的两个对象的堆内存地址,如果相等,则说明这两个引用实际是指向同一个对象地址的
  • 在Object类型的equals方法是直接通过==来比较的,和==是没有任何区别的。当我们重写了equals方法时,它可以用来比较两个对象的内容是否相等。

18、abstract 和final能同时使用吗

        不能,因为抽象类就是为了定义一种约定,好让子类去实现该约定,而final修饰的类不能被继承。

19、抽象类和接口的关系和区别

  • 区别:
    • 接口:只包含抽象方法、静态方法和默认方法,不能为普通方法提供方法实现。而抽象类完全包含普通方法;
    • 接口:只能定义静态常量,不能定义普通成员变量。而抽象类既可以定义普通成员变量,也可以定义静态常量
    • 接口:不能包含构造器。而抽象类可以包含构造器(让抽象类的子类调用这些构造器来完成属于抽象类的初始化操作)
    • 接口:不能包含初始化块,而抽象类可以包含初始代码块。
    • 接口:多实现,而抽象类单继承,包括抽象类
  • 联系:
    • 都不能被实例化;
    • 都位于继承树的顶端,用于被其他类实现和继承;
    • 都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法。

 20、Mybits中${}和#{}的区别

  • #{}匹配的是一个占位符,相当于JDBC中的一个?会对一些敏感的字符进行过滤,编译过后会对传递的值加上双引号,因此可以防止SQL注入问题。
  • ${}匹配的是真实传递的值,传递过后,会与sql语句进行字符串拼接。${}会与其他sql进行字符串拼接,不能预防sql注入问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值