java某些知识点总结

1.如何最快计算出2*8(即2的四次方)

2>>4(左移):因为位运算是CPU直接支持的,所以运算效率最高

2.collection和collections的区别

Collection:集合类的上层接口,继承它的主要接口有List和Set集合接口。

Collections:集合工具类,它封装了一系列的静态方法,提供给集合做搜索、排序、线程安全等功能。

3.java线程

1)我理解的概念:线程就是用来运行程序的,能过运行一个以上的程序就叫多线程。

2)线程安全性的5种类别

    ①不可变:不可变的对象一定是线程安全的,如Integer,String等。

    ②线程安全

    ③有条件的线程安全

    ④线程兼容:线程兼容不是线程安全的,但是可以使用同步在并发环境中安全的使用。

    ⑤线程对立

3)简单理解线程池

    ①线程池是为了解决什么问题的?答:处理器单元内多个线程执行的问题。可以减少处理器闲置的时间,增加吞吐能力。

    ②线程池是如何解决问题的?

        一个线程完成一个任务所花费的时间有:T1(创建线程的时间),T2(执行任务的时间),T3(销毁线程的时间)

        如果有:T1+T3 >T2:可以采用线程池提高服务性能

        线程池的组成部分:

        a:线程池管理器(ThreadPool):创建线程池并管理线程池,创建线程、销毁线程、添加任务。

        b:工作线程(PoolWorker):在没有任务的时候就等待任务,可以循环的执行任务。

        c:任务接口(Task):每个任务都必须实现此接口,以便工作线程调度任务的执行。

        d:任务队列:(taskQueue):用于存放未处理的任务,用于缓冲。

    注:线程池技术关注的就是如何缩短T1,T3时间的技术,从而提高服务器程序的性能。

4.GC垃圾回收机制

垃圾回收机制需要了解的几个问题:

    1)什么是堆内存?

    2)什么是垃圾?

    3)有哪些方法回收这些垃圾?

    4)什么是分带回收机制?

1)什么是堆内存?

    堆是在JVM启动时创建的,主要是用来维护运行时数据。如运行时创建的对象、数组都是基于堆内存的。

2)什么是垃圾?

    所谓的垃圾:不在存活的对象。常见的判断依据:引用计数法、可达性分析。

    引用计数法:无法检测循环引用,因此在java中没有采用此次方法来判断对象的“存活性”。

    可达性分析:把所有对象想象成一棵树,从根节点GC Roots出发,遍历找出所有连接树枝的对象,这些对象则被称为可达对象,其余对象则被称为“死亡”、“不可达”或“垃圾”。

    GC Roots对象又是指谁呢?首先GC Roots一定是可达的,这样一来java中有哪些对象一定是可达的?有以下四种

        a:虚拟栈中引用的对象。

        b:方法区中静态属性引用的对象。

        c:方法区中常量引用的对象。

        d:本地方法栈中JNI引用的对象。

3)有哪些方法来回收这些垃圾呢?

    ①标记-清理

        a:第一步:标记:利用可达性遍历堆内存,将“存活”对象和“垃圾”对象进行标记。

        b:第二步:从第一部得到被标记的“垃圾”,所以直接将“垃圾”对象占用的空间清空。

    注:标记-清理容易产生内存碎片。

    ②标记-整理:在清理“垃圾”的时候,将“存活”对象扎堆到同一个地方,这样就不存在内存碎片了。

    注:①②两种方法只适合“垃圾”少的情况,因为只需要清理少量的垃圾,挪动一下存活对象就行了。

    ③复制

    简单粗暴:把堆分成两个部分,在一段时间内只允许在一块内存上进行分配,在内存分配完之后就行垃圾回收,将所有存活对象复制到另一块内存,然后直接将本块内存清空。

    注:这种方法因为将内存对半分,可能会导致频繁的进行“复制-清空”操作。因此这种方法适合:垃圾多,存活少的情况,只需要复制少量对象,然后清空。

4)java的分代回收机制

    以上三种回收机制在java中如何进行选择的呢?首先先看看java堆内存的结构:

    java堆内存的结构:用来存储三类数据

        ①刚刚创建不久的对象。程序运行时会不断创建新对象,但是创建和不久就编程不可达对象,这种现象属于:垃圾多,存活少。这块区域也被叫做:新生代。

        ②存活了一段时间的对象。这种现象属于:存活多,垃圾少。被叫做:老年代。

        ③永久存在的对象。永久代。

    因此总结下来:常规的java堆包括:新生代,老年代两块区域,而这两块区域有着明显的特点。通过他们的特点就可以得到一些回收方案如下:

        ①新生代:复制-回收机制:如何设计复制-回收机制?

            a:内存均分1:1的比例

            b:内存9:1比例:存在的隐藏问题:当将9区对象复制到1区,1区内存不够,就需要将剩下的放入老年区,但有可能这些对象不是老年对象,所以破坏了老年区的规则。

            c:有了b的问题得出一种方法:内存8:1:1比例分:思路:8区内存满时,清理8区,将存活对象放入其中一个1区,清空8区,然后再当8区满时,同时清理8区和1区,将存活对象放入另一个1区,如此反复进行,进行多次后就可以判断1区中的对象为老年对象,即可放入老年区。

        ②老年代:标记-整理机制

标注我的理解:分代回收:即分为新生代,老年代,然后对此采用不同的回收机制。

5.Java NIO

NIO是通过Channel+Buffer来实现的。

Buffer:数据缓冲区,他可以被理解为一个数组。常用的是:ByteBuffer。

1)Buffer中的三大重要属性:position(位置)、limit(限制)、capacity(容量:被初始化后就不能改变)

position:初始值为0,向其中写入一个值position就加1,如果需要读数据,首先需要flip,然后position被重置为0,就可以读取数据,读取一个值position也加1。

limit:写的时候与capacity一样,读的时候为数据的实际大小。

2)Channel:所有NIO操作始于通道。通道是数据来源或数据写入的目的地,常用的几个Channel有:

    ①FileChannel:文件通道(不支持非阻塞)

    ②DatagramChannel:数据包通道,用于UDP连接的接收和发送

    ③SocketChannel:连接TCP的通道(TCP客户端)

    ④ServerSocketChannel:TCP对应的服务端,用于监听某个端口进来的请求 

3)Selector选择器或多路复用器

    运用非阻塞模式,需要将Channel注册在Selector上,因此需要支持非阻塞,所以讨论的是SocketChannel和ServerSocketChannel。注册完成之后,需要将阻塞模式显示设置为“非阻塞模式”,因为默认的模式是“阻塞模式”。然后就可以注册感兴趣的事件,就可以实现事件的接收。

6.MyBatis的缓存

1)一级缓存

    ①什么是一级缓存?为什么使用一级缓存?

        使用MyBatis开启一次数据库会话,MyBatis会创建一个SQLSession对象表示一次会话。

        使用一级缓存是为了解决什么问题?因为在一次会话中,如果有多次反复查询同一条数据,而这条数据在这段时间没有任何改变,那么每一次查询都需要与数据库建立一次连接,那么会极大的消耗资源,并且降低运行的性能。

        如何解决这个问题?所以为了解决这一为题,减少资源的浪费,MyBatis在SqlSession对象中建立一个简单的缓存,将查询结果缓存起来,如果再有相同的查询就直接从缓存中获取,就不需要进行数据库查询了。

    注:一级缓存是会话(session)级别的缓存。

    ②一级缓存是怎样组织的?

        对于会话级别的的一级缓存是在SqlSession中控制的,SqlSession是MyBatis对外的一个接口,SqlSession将它的工作交给了Executor执行器来完成,负责完成对数据库的各种操作。创建一个SqlSession对象时,MyBatis会为这个对象创建一个新的Executor执行器,而缓存信息就被维护在这个执行器中。Mybatis将缓存和缓存相关的操作放在了Cache接口中。

    ③一级缓存的生命周期有多长?

       a:Mybatis开启数据库会话时会创建一个SqlSession,SqlSession对象中有一个Executor对象。Executor对象中持有一个PerpetualCache对象,当会话结束时,SqlSession对象以及其内部的Executor对象和PerpetualCache对象也一并释放掉。

        b:如果SqlSession调用close方法,会释放掉一级缓存PerpetualCache,一级缓存将不可用。

        c:如果SqlSession调用了clearCache方法,会清空PerpetualCache的数据,但该对象还是可用。

        d:SqlSession执行任何一个update(update,delete,insert)操作,都会清空PerpetualCache对象,但对象还是可用继续 使用。

2)二级缓存:避免使用

    二级缓存只适用于单表操作,而且与单表有关的操作必须在一个namespace下,不然都会引起危害。因为在每个namespace下的操作时相互独立的,每个namespace下的update操作只会清空该空间的缓存,如果存在多表操作,本namespace下修改了数据只清空了本namespace下的缓存,而其他namespace下的缓存没有被清空,然后其他namespace里面的操作有关联到本表,所以会导致数据的不一致。所以需要避免使用二级缓存。

7.RestFul风格

    基于HTTP协议的实现,统一数据操作的接口,仅通过HTTP方法就可以完成数据的增删改查,针对不同的请求方式(get,post,put,delete)实现不同的操作。因此HTTP协议就是一种restful风格。

    restful风格,就是一种面向资源服务的API设计,不是规范,不是标准,而是一种设计方式。

    考虑一下两个问题:
        1.对于用户登录和用户退出这两个业务需求,REST指导下的架构和设计如何满足
        2.批量的删除、修改、新增如何满足

8、String、StringBuffer和StringBuilder

运行速度:StringBuilder > StringBuffer > String

String最慢的原因:String为字符串常量,另外两个是字符串变量,即String对象一旦创建之后是不能改变的,另另个是可以更改的。

线程安全层面:StringBuilder是线程不安全的,而StringBuffer是线程安全的。

如果一个StringBuffer在字符串缓冲区被多个线程使用时,StringBuffer中有很多方法可以带有synchronized关键字,所以保证线程是安全的,但StringBuilder的方法没有该关键字,所以不能保证线程安全。所以如果要进行的操作是多线程,那么就要使用StringBuffer,但是在单线程的情况下,建议使用速度比较快的StringBuilder。

总结:

String:适用少量字符串操作的情况

StringBuilder:适用于单线程在字符缓冲区进行大量操作的情况

StringBuffer:适用于多线程在字符缓冲区进行大量操作的情况

9、队列与栈

Queue:队列是一个FIFO的数据结构,Queue接口与List、Set同一级别,都是继承了Connection接口,LinkedList实现了Deque接口。

没有实现阻塞接口的LinkedList:内置不阻塞队列:PriorityQueue和ConcurrentLinkedQueue。

Queue使用时尽量避免Connection的add()和remove()方法,而要使用offer()来加入元素,使用poll()来获取并移除元素,他们的优点是通过返回值可以判断是否成功,add()和remove()在方法失败的时候回抛出异常。

LinkedList实现了Queue接口,因此可以吧LinkedList当做Queue来使用。

Deque双端队列,继承Queue,直接实现它的有:LinkedList,ArrayDeque,ConcurConcurrentLinkedDeque等。

Deque可以当做队列使用(先入先出),也能当栈使用(先入后出)。

Deque的实现类主要分为两种场景:

一般场景:

  • LinkedList大小可变的链表双端队列,允许元素为null
  • ArrayDeque大小可变的数组双端队列,不允许null

并发场景:

  • LinkedLinkedBlockingDeque如果队列为空,获取操作将会阻塞,直到元素添加

Stack栈:栈是Vector的一个子类,方法简介:

  • boolean empty():堆栈是否为空
  • Object peek():查看堆栈顶部的对象,但不移除
  • Object pop():移除堆栈顶部的对象,并作为此函数的值返回该对象
  • Object push(Object ele):把项压入堆栈的顶部
  • int search(Object ele):返回该对象在堆栈中的位置,以1为基数

猜你喜欢

转载自blog.csdn.net/qq_37978623/article/details/80688441
今日推荐