Java学习笔记

笔记 专栏收录该内容
7 篇文章 0 订阅

Java学习笔记(一些在学校可能接触不到的知识)

备注:是一位优秀的师兄分享给我的,我认为总结得还不错,所以这里也和大家分享下,喜欢的同学可以共同学习下,有哪里不对的也可以在下方评论下哦。


学习内容:

1、 java基础知识
2、 JVM体系知识
3、 SSM框架体系知识
4、 Java锁体系知识
5、Java线程体系知识
6、Java运维知识
7、数据结构


Java基础知识:

【Java基础知识】
补充:
Java中判断两个变量是否相等有两种方式:一种是利用双=运算符,另一种是利用equals方法。如果变量是基本类型,那么使用双=和使用equals会得到相同的结果,都是判断变量的值是否相对。如果变量是引用类型,双=运算符判断变量是否指向同一引用对象,equals判断变量"值"是否相等。Java值类型对应的包装类(Boolean、Byte、Short、Integer、Long、Float、Double、Charcater)可以利用==运算符进行值判断。
在这里插入图片描述
++a优先级比乘除高,然后a++的话,先去a的值,然后运算后再进行++,如a++/b++,那么一开始是计算a/b的结果,然后再对a和b进行自增

(1)java中的static为静态修饰符,类加载后会分配静态地址,可以通过类成员 进行访问,不需要实体化一个变量。Static不随变量消亡而消亡,而随着类消亡而消亡。Abstract修饰的类称为抽象类,抽象类中可以有抽象方法(用abstract修饰的类),也可以有非抽象方法。抽象类不能被实例化,只能被继承,然后子类重写抽象类的抽象方法后,子类被实例化。
(2)继承问题:private 不能被继承,protected变量或方法被继承后,在子类只能申明成更加开放的修饰符比如protected和public。而public被继承后只能申明为public。
此外,类和接口只能定义为public。
(3)运算符这一节:instanceof判断是否为一个类的对象。
(4)获取数组的长度:array.length即可。多维数组定义有多种方式,如下:
在这里插入图片描述
(5)日期:获取当前日期方法,先定义一个日期对象,然后data.toString()就可以获得当前日期。
(6)JAVA IO:了解几个类,inputstream,fileinputstream,
outputstream,fileoutputstream,reader,filereader,writer,filewriter。前面四个是处理字节的,后面四个是处理字符的。

其中inputstream和reader都是输入流,但不是输入文件,而是从文件读取内容,输入到流中,因此这两个类都有一个read()函数,而对于fileinputsream和filereader,一搬单独定义这两个类的对象作用不大,而是用inpurtstream=fileinputstream(“文件路径”)的方式,后期操作inputstream。

其中outputstream和writer都是输出流,但是都是输出到文件,所有都有一个write()函数,可以写入文件中。其他同上。

此外,还有两个比较重要的类,就是inputstreamreader和outputstreamwriter,作用是因为inputstream只能以字节的形式进行操作,而如果要对inputstream对象进行字符操作,则需要使用inputsreamreader,例如:
File f = new File(“a.txt”);
FileInputStream fop = new FileInputStream(f);
InputStreamWriter writer = new InputStreamWriter(fop, “UTF-8”);
reader.append(“中文输入”);
reader.append("\r\n");
这样就可以实现对inputstream进行字符的操作了。

此外对于outputstreamwriter也是同样的道理。

(7)关于继承:继承没有什么好说的了,java支持单继承,其他只能以接口的形式继承
(8)关于重写:重写的实质是,让子类中的函数覆盖父类中的同名函数,因此函数参数列表不能变。只能重写实现方式。java中重写的几点要求:一、函数参数列表和父类一样。二、访问权限必须更高。三、返回类型可以和父类不一样,但是必须是父类返回值的派生类。(特殊)
(9)关于重载:对于重载,其实就是用同一个函数名,实现不同的函数功能,因此函数参数列表必须不同,而返回值,访问权限等都可以改变。

(10)多态:父类引用指向子类对象。
在这里插入图片描述在这里插入图片描述
(11)抽象Abstract:一、抽象类不能定义 ,只能被继承使用。但是可以使抽象类指向自己的子类对象。二、定义了抽象方法的类必须是抽象类,但是抽象类中不一定有抽象方法,但是如果有抽象方法的抽象类,被继承后,子类必须实现他的抽象方法。

(12)封装:就是将一些关键数据定义成private,然后用setter和getter的方式来开放接口。

(13)接口不能被实例化,但是可以被实现。实现接口的类必须实现接口全部的函数,否则就要定义为抽象类。接口是可以多继承的。

(14)泛型:
泛型方法:对一个方法使用泛型,有点类似于模板方法,应用于比如不知道该方法要处理哪个数据类型的时候,这时候可以写一个泛型方法,可以通用所有类型的参数。比如下面:
在这里插入图片描述
泛型类:相当于模板类,比如这个类里面可能有一些变量或者方法,不知道用什么类型,这时候就可以用泛型类来做。如下:
在这里插入图片描述
类型通配符(常用于java的一些集合框架如list,map等)
对于一些集合框架,比如list,如果想要存放特定的数据类型,比如只存int,则可以定义为List list = new List(); 其他使用方法如下图:
在这里插入图片描述
(15)序列化:实际上就是让一个类A继承一个实现序列化的类B,然后这个类A就可以被转化成字节的形式被存储起来,存储到文件中,当需要的时候,可以从文件中读出并转换成一个类。

(16)java网络编程:实际上讲得就是TCP和UDP通信。首先是套接字Socket编程。也就是服务器端先建立一个ServerSocket套接字,指定自己的IP和端口,然后一直调用accept()函数等待客户端进行连接,客户端创建一个套接字Socket,指定服务器的地址和端口,然后就进行连接。连接成功后,服务器和客户端分别会有一个输入流和输出流,客户端输入流对应服务器输出流,服务器输入流对应客户端输出流,可以相互传输数据。

(17)多线程编程:两种方法,实现Runnable接口和继承Thread类。但实际上都是通过创建Thread实例,然后运行多线程的。

(18)数据库连接:这个不难,需要用的时候看一下就可以了
关于java mysql数据库链接部分的执行语句知识点(statement、preparedstatement、callablestatement)
可参考: https://blog.csdn.net/nfzhlk/article/details/83416413

(19)关于HasMap:
1、hashmap默认初始长度为16,而且长度必须为2的幂。(可以自动扩充也可以手动初始化),hashmap里面存储的是键值对的。用put和get方法添加和取出。
在这里插入图片描述
附加问题:为什么在java8以后,hashmap中使用红黑树,而不是AVL树?
回答:相比于AVL树,红黑树在与AVL树查找性能相差不大的同时,又保证了插入修改的次数只需要在3次操作内实现,提高了修改的效率。
2、当Hashmap在插入元素过多的时候需要进行Resize,Resize的条件是
HashMap.Size >=Capacity*LoadFactor。
Hashmap的Resize包含扩容和ReHash两个步骤,ReHash在并发的情况下可能会形成链表环。(也就是当hashmap长度不够用的时候,首先是创建一个新hashmap,长度为原来的2倍,再将原来的hashmap重新hash到新的hashmap中)

3)haspmap有一个缺点是:当高并发的时候,不是线程安全的。(因为线程时间片会用完,而且没有加锁,当执行操作过程中可能出现问题。)所以如果是高并发的情况下,要用ConcurrentHashmap。

4)ConcurrentHashmap相当于一个二级哈希表。

在这里插入图片描述
(20)HashMap 的长度为什么是2的幂次方:
因为在求某个key对应的hashmap数组下标索引的时候,都是用hash值取余数组的长度,但是这种计算速度慢。如果数组长度是2的幂次方的话,就可以使用hash值和数组长度减1的二进制进行与运算,得到的结果和取余相同,但是速度特别快。所以决定长度为2的幂次方。而且在扩充长度的时候,也是以2倍的形式扩充。

(21)HashMap和HashTable的区别:
1、hashmap不是线程安全的,hashtable是线程安全的(所有读写操作都加锁)。
2、hashmap键值都可以为空,hashtable不可以。
3、因为线程安全、哈希效率的问题、hashmap的效率是比hashtable的要高。
注意:HashTable和HashMap的数据结构实际上都是相同的,方法也是相似的,只是HashTable的操作是加锁的。
在这里插入图片描述
(22)ConcurrentHashMap和HashTable的区别:
1)HashTable使用synchronized关键字进行加锁。对整个对象加锁,当hashtable的大小增加到一定的时候,急剧影响性能。
2)ConcurrentHashMap完善了上面的功能。在它里面定义了多个segment(默认是16个),每个segment相当于是一个hashtable,因为里面的结构跟hashtable相似,而且concurrenthashmap加锁的方式,也是对某一个segment加锁,而不是对整个map加锁,因此效率高。其中用每个key对应的hashcode的高位代表是哪个segment。而对于remove删除操作,因为segment中的每个数组的值是一个链表,而且这种链表特性是不变性,即next指针不变,因此remove操作后,对应节点前面的节点需要复制一遍,并采用头插法重新生成一个新的链表,并接上后面的链。

补充:CAS(Compare And Swap比较并替换)
在这里插入图片描述在这里插入图片描述
(23)对java中的集合进行归纳:
1)java中集合分为两类:Collection类和Map类。
2)泛型:java的集合经常要用到泛型,在定义一个集合的时候,最好也写出对应的泛型,不然在后面使用的时候无法向下转换成泛型对应的类型。
3)Collection和Map区别:collection为单列,map为双列(键:值)。Collection中list可重复,set不可重复。Map键不可重复,值可以重复。
4)Collection中包括list和set两种。其中list(列表)存储有序,set(集合)存储无需。此外,对于Collection类的集合,增加用add()函数,删除用remove()函数,并且会返回。
5)List包括ArrayList和LinkedList和Vector(淘汰)。ArrayList底层用数组实现,方便查找,不方便增删。LinkedList底层链表实现,方便增删,不方便改查。常用操作包括:add()添加, remove()删除。
6)Set包括HashSet,LinkedHashSet,TreeSet。对于HashSet(有固定数组长度),存储无序,不可重复。对于LinkedHashSet,由于是链表和哈希共同实现,所以是存储有序,不可重复的。TreeSet底层是二叉树实现的,存储的时候可以无序,但是由于存的时候,会自动进行排序,所以取出来的时候是有序的(如果要实现排序,直接将其存到TreeSet中再取出来即可。),但是由于TreeSet没有Hash的功能,所以如果要实现不可重复,必须在创建的时候传入比较器实现不可重复。
7)Map包括HashMap,LinkedHashMap,和TreeMap(和set相似)。其中HashMap是键值不可重复的,无序的。LinkedHaspMap因为有链表支撑,所以存入跟读出的顺序是相同的。TreeMap想要实现排序,也需要传入比较器。Map存入的时候以键值对的时候存入,用put(key,value)函数,读出要用迭代器读出。定义map的时候,泛型需要定义两个,一个是键的泛型,一个是值的泛型。
8)实现哈希的方法是:(hashcode()函数和equals()函数一起的作用),首先对要存储的对象求出对应的hashcode值,然后结合数组长度求出其存储的下标,如果该下标位置空,则直接存储,如果不为空,则需要用equals对两个对象进行对比,如果相同,则不操作,如果不相同,则添加到这个下标的链表头(头插法)。
在这里插入图片描述
9)HashMap和HashTable的用法其实基本是相同的,只是在部分地方有所不同。

(24)说说Iterator和ListIterator的区别?
在这里插入图片描述
(25)String(字符串常量)、stringBuffer(字符串变量,线程安全)、StringBuilder(非线程安全)对比区别:
1、string进行拼接的时候,其实每次都是新建一个对象,然后指针指向新的对象。但stringBuffer不是,是在原来的引用上进行操作。(底层是一个不可变的字符数组final型的)

2、stringBuffer是变量,引进stringbuilder的原因是:stringbuffer虽然是线程安全的(在append函数前用了sync锁),适合用于多线程的情况下,但是在单线程的情况下性能不高,而stringBuilder跟stringBuffer操作基本相同,非线程安全,在单线程下效率更高。是语法方面,stringBuffer和stringBuilder几乎没有差别。(底层是可变的字符数组)

(26)Volatile变量的用处:
当对非volatile变量进行读写的时候,每个线程先从主内存拷贝变量到CPU缓存中,如果计算机有多个CPU,每个线程可能在不同的CPU上被处理,这意味着每个线程可以拷贝到不同的CPU cache中。
volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,保证了每次读写变量都从主内存中读,跳过CPU cache这一步。当一个线程修改了这个变量的值,新值对于其他线程是立即得知的。
补充:volatile如何确保可见性
在这里插入图片描述


JVM体系知识

1、关于JVM的一些知识:(https://www.cnblogs.com/sunada2005/p/3577799.html非常重要)
在这里插入图片描述在这里插入图片描述
本地方法栈的作用:作用是支撑Native方法的调用,执行和退出

JVM相关知识:
1、组成:由4大部分组成:Class Loader类加载器、Runtime Data Area运行数据区域、Execution Engine运行引擎、Native interface 本地接口。

类加载器作用:加载class文件,只负责加载,是否运行由执行引擎决定。
本地接口作用:负责调用本地接口,他会在Runtime data Area的Native method Stack中记录接口方法,调用不同语言的接口给java用。实际过程中,是通过运行引擎加载本地lib文件后,才可以调用接口给java用。
执行引擎作用:在Class文件加载后,会把数据信息以及指令存放到内存里面,执行引擎就负责把这些指令解释给操作系统。
Runtime Data Area是负责存放数据的,关于java的所有内存数据,基本都存放到这一块。

2、JVM运行原理解释:
首先,java文件被编译器javac工具编译成.class字节流文件,然后.class字节流文件被JVM编译成机器码。这个过程中JVM分配内存并运行程序。

3、JVM垃圾回收:(了解一下)
JVM中会在以下情况触发回收:对象没有被引用,作用域发生未捕捉异常,程序正常执行完毕,程序执行了System.exit(),程序发生意外终止。JVM中标记垃圾使用的算法是一种根搜索算法。

4、JVM内存管理:重点管理Heap和Stack即可。

关于JVM的运行时数据区域:
(1)堆和方法区是共有。
(2)虚拟机栈、本地方法栈和程序计数器是线程私有的。

在一个线程里:
包含程序计数器(里面放的是接下来要执行的指令的序号、按理是连续的)、本地方法栈(因为java底层是C++,所以已经有很多源码了,有些方法不需要java自己写,所以本地方法栈里面存放的就是这些源码—也就是存放一些native方法。)和JVM栈(虚拟机栈)。在虚拟机栈里面,有很多个栈帧,每个栈帧对应一个方法(函数)。栈帧里面包含局部变量表(存储函数里定义的局部变量)、操作数栈(跟CPU计算打交道,当需要计算的时候,会先从局部变量表取值复制到这里,然后从这里再取值出来到CPU进行运算,并将结果返回到这里)、动态链接(在运行期间,由符号引用转化为直接引用的过程,叫动态链接)、方法出口(也就是存储返回地址的地方,比如一个函数调用了这个方法,则需要返回值给另外一个函数,所以这里存了指针指向那个函数)。

对于堆:JVM启动的时候自动分配。存储的是对象的实例,几乎所有的对象都是堆在分配内存。当对象无法申请内存时,会报出outofmemoryerror错误。

对于方法区:关于类的所有字段、信息都存储在方法区。也就是所有定义的方法信息都保存在这里,包括静态变量、常量、类信息、常量池等。

JVM调优:吞吐量以及停顿时间(也就是当老生代的空间满了,就会出现垃圾回收,这个时候的垃圾回收机制叫做MajorGCC,会把新生代和老生代的区域都回收,同时会发生STW,StopTheWorld,也就是停止用户的线程不运行,专门用来垃圾回收,这个时间就是停顿时间)
在进行fullGC 和minorGC的时候会STW,因为不停止线程,则在GC过程中,找到的有用链可能又被破坏,导致GC过程出现不干净等问题。


SSM框架体系知识

Spring编程:Spring事务的传播特性和隔离级别
可参考:https://blog.csdn.net/claram/article/details/51646645
(1)7大特性、5大隔离级别(跟5大数据库事务隔离级别类似)
Servlet与cgi的区别:
可参考:https://blog.csdn.net/DLUTBruceZhang/article/details/49933357
都是处理客户端提交请求到服务端响应的问题。对CGI,是请求交给服务器,服务器转给CGI,CGI处理返回给服务器,服务器返回给客户端。(CGI就相当于一个第三方的处理工具)对于Servlet,客户端提交请求给服务器,服务器调动产生servlet,servlet将处理结果返回给服务器,服务器返回给客户端。(而Servlet就是一个服务器上的程序,帮服务器处理问题)
Servlet处理效率高,有更好的可移植性。
对于CGI,每个请求都要启动一个新的CGI进程。而对于servlet,一个进程处理所有的请求。资源利用率更高。

Servlet生命周期可参考:https://www.runoob.com/servlet/servlet-life-cycle.html
通过调用init()函数创建。
过程中调用service()函数来处理客户端请求,根据客户端传来的请求类型调用doGet()、doPost()等函数。
当请求结束后,调用destroy()函数终止servlet。
JVM垃圾回收。

(2)
快速失败(fail—fast):
在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行了修改(增加、删除、修改),则会抛出Concurrent Modification Exception。称为快速失败。
场景:java.util包下的集合类都是快速失败的,不能在多线程下发生并发修改(迭代过程中被修改)。

安全失败(fail—safe)
采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。
缺点:基于拷贝内容的优点是避免了Concurrent Modification Exception,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。

总结:快速失败和安全失败是对迭代器而言的。快速失败:当在迭代一个集合的时候,如果有另外一个线程在修改这个集合,就会抛出ConcurrentModification异常,java.util下都是快速失败。安全失败:在迭代时候会在集合二层做一个拷贝,所以在修改集合上层元素不会影响下层。在java.util.concurrent下都是安全失败。

什么是SSM框架:
1、Spring:里面有很多核心容器(比如core/beans/context/context-support/experssion这些)。Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
2、Spring MVC 分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。
3、MyBatis是Apache的一个基于Java的持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。

对servlet的理解:
1、servlet是server Applet的缩写,是由java编写的服务端程序,这些servlet都要事先servlet接口。主要功能在于交互式地浏览和修改数据,生成动态web内容,servlet运行于支持java的应用服务器中。
2、HttpServlet,通过重写doGet和doPost,或者重写service方法完成对get和post的请求。

Forward和redirect的区别:
1、forward还是原来那个请求,只是服务器端将需要跳转到的页面信息返回给客户端,客户端浏览的地址不会改变,这样有利于隐藏实际的地址,而且效率相对更高。
2、redirect是浏览器会得到需要跳转到的那个地址,然后重新发起请求,服务器返回相应页面,所以地址栏的地址会改变。

Servlet和jsp区别:
1、jsp实际上是继承了servlet的。但是jsp是HTML和java组合子在一起的一个文件,侧重于视图,而servlet更加侧重于逻辑。

Cookie工作原理:
1、服务器创建生成一个Cookie,并且添加到response中,然后当浏览器访问的时候,会发送给浏览器,浏览器接受并存到浏览器中。
2、同类请求(资源路径相同的请求)的时候,浏览器会将上一次获取到的cookie发送给服务器,并且服务器此时不会再返回一个新的cookie。
3、如果要指定cookie绑定路径,则需要在服务端指定的路径前动态加上项目名称(request.getContextPath())。此时是cookie是保存在缓存中。
4、如果要将cookie写入硬盘中,则需要给cookie添加有效期。
5、如何使用cookie? 在第一次浏览器访问某个网页的时候,如果生成了cookie并返回给浏览器,下一次浏览器发送同类请求的时候,就会将cookie发送给服务器,此时服务器就可以接收到cookie,并取出里面的值,进行一系列相关操作。

Session的工作原理:
1、对于session,不同会话会创建不同的session。
2、服务器每次创建一个session,都会将一个新的session写进一个session列表(map),session列表是一个map,服务器鉴别不同session的方式就是通过每个session对应不同的key(32位长度),从而获取到每个session的引用。
3、服务器在将session写进session列表以后,会将session的key作为一个值,以jsessionID为key,将这个键值对随着cookie一起发给客户端浏览器,被客户端浏览器保存在浏览器缓存中,当会话结束的时候,这个cookie也就消失了。
4、当下次浏览器访问这个服务器的时候,会将之前存的session的jsessionID一起发送给服务器,此时,服务器会获取到浏览器发过来的jsessionID,然后获取对应的值,再到服务器的session列表中找对应jsessionID的value值,也就获取到了对应的session,就可以获得session中的值了。

Session失效原理:
(1)默认从最后一次访问开始计时,如果session的时长超过30分钟,这个session就会消失。但是可以人为设置,根据具体的实际应用场景,可以设置session的失效时长。
(2)

Cookie禁用后使用Session进行会话跟踪:
1、由于Cookie禁用后,服务器发过来的cookie不能再被客户端接受,所以下一次发送请求给服务器的时候,不会将上一次的jsessionID发给服务器,服务器会重新生成一个session给浏览器。
2、但是即使Cookie禁用,仍然可以访问到原来创建的那个Session,只需要在浏览器访问服务器的地址后面加上“jsessionID=xxx32位长的IDxxx”,就可以访问到刚刚那个session了,相当于还是在操作刚刚那个会话,因此这个是一个危险的操作。
3、对于客户端而言,一个会话的结束就是从开启一个浏览器到关闭一个浏览器的过程。但是对于服务器而言,一个会话是从session建立到session生命周期结束的时候,也就是将session清掉的时候,即使浏览器关闭,session仍然可能存在。
4、在重定向的时候,可以通过解析url去实现session会话跟踪的目的
5、非重定向的时候,也要通过解析url去实现session会话跟踪的目的

Cookie和Session的比较:
1、session保存在服务器端,是安全的,但是当访问过多,影响服务器性能。
2、Cookie保存在浏览器端,是不安全的,但是不影响服务器性能。
3、单个Cookie不能超过4K内容,而且一个站点最多保存20个Cookie。
4、个人建议:将登录信息等重要信息放到Session中,将其他信息可以放到Cookie中(比如购物车)。
5、如果禁用了浏览器的Cookie,可以采用Cookie+数据库的方式来处理。Cookie中没有的信息就访问数据库。

MVC模式?
1、Model模型:javabean
2、View视图: html/jsp/freemarker
3、Control控制器:Servlet/Action
最经典的MVC模式::jsp+Servlet+javabean

文件描述符的概念:
Linux 系统中,把一切都看做是文件,当进程打开现有文件或创建新文件时,内核向进程返回一个文件描述符,文件描述符就是内核为了高效管理已被打开的文件所创建的索引,用来指向被打开的文件,所有执行I/O操作的系统调用都会通过文件描述符。


Java锁体系知识

Java锁相关知识:
1、java对象(对象布局)由三部分组成:
(1)对象头:固定12个byte
(2)实例数据:可变的。根据自己类定义的属性来变动。
(3)对齐数据:因为java对象必须是8的整数倍个byte,如果前两部分没达到的话,就会用这部分进行填充。

2、什么是java对象头?
Java对象头就是出于java对象布局最前面的12个Byte的数据,包含了一系列信息(其中包含了一些java锁信息等等)。

3、Synchronized和Lock有什么区别?
(1)synchronized是关键字,JVM级别的关键字,而Lock是一个API,java.concurrent包下的API。
(2)synchronized不会产生死锁的情况,因为底层用来两次monitorexit,即正常退出和异常退出,所以一定不会产生死锁的情况。但是对于Lock的话,需要自己释放锁。
(3)对于synchronized不可中断,但是Lock可以中断。
(4)加锁是否公平:synchronized是非公平锁,但是ReentrantLock两者都可以,创建的时候需要传入boolean值,默认为false,即为非公平锁,传入true为公平锁。
(5)锁绑定多个条件Condition:synchronized没有绑定条件。ReentrantLock用来实现分组唤醒需要唤醒的线程们,可以精确唤醒。不像是synchronized一样,要么随机唤醒,要么全部唤醒。
在这里插入图片描述
引出题目:多线程之间顺序调用,实现A->B->C三个线程启动。
https://www.cnblogs.com/xiaoxi/p/7651360.html 讲得很好,关于ReentranLock 和 Condition的内容。

死锁定位分析:通过JPS找到目前发生故障的进程号,用Jstack查看当前进程号的故障,便可以找到死锁的问题。


Java线程体系知识

实现一个拷贝文件的工具类使用字节流还是字符流?
解答:我们拷贝的文件不能确定是只包含字符流,有可能有字节流(图片、声音、图像等),为考虑到通用性,要使用字节流。因为字节流比字符流更小(一个字符=两个字节,肯定是要用更小的单位更好)

1、线程如何启动?
解答:Thread thread = new Thread(“继承了Thread类的一个子类,并且在该子类中要有run函数”)。
thread.start();通过start方法启动,启动后调用的是run方法。

2、如何区分每个线程?
解答:给每个线程设定一个名称。如:thread.setName(“名字”);

3、什么情况适合用线程池?
解答:单个任务的处理时间比较短。(如何每个线程要很久,就不适合)
需要处理的任务量很大。(比如电商项目的下单)

4、线程池有哪些创建方式?
回答:一共有5钟,常用的有3种。
(1)第一种:newFixedThreadPool(int num)。固定一个线程池有num个线程,适用于执行长期的任务,性能好很多。
(2)第二种:newSingleThreadPoolExecutor()。只有一个线程,适用于一个任务一个任务去执行的场景。
(3)第三种:newCachedThreadPool()。一个线程池多个线程,适用于执行很多短期异步的小程序或负载较轻的服务器。

5、线程池原理及线程池的七大参数:(一般面试会只问前5个,但是后2个是源码的内容)
(1)corePoolSize:是线程池中的核心线程数,优先用这些线程去处理。
(2)maximumPoolSize:是线程池中能够容纳的最大线程数,包括核心线程,剩余的是当核心线程忙不过来的时候(即当阻塞队列满而且核心线程也在工作的时候),会调用的剩余线程。
(3)keepAliveTime:当任务量已经处理完了,而且已经到了keepAliveTime的时间后,如果还是没有多余的任务,那么多余的线程将会被销毁直到剩下核心线程。
(4)unit:第三个参数的时间单位。
(5)BlockingQueue:阻塞队列。当任务大于最大线程数的时候,剩下的任务会被放到阻塞队列里面进行等待。
(6)threadFactory:表示创建线程的工厂。用默认值即可。
(7)handler:拒绝策略。即目前所有线程都在处理任务,而且阻塞队列中也满了,那么再来的任务,将会由handler采取的拒绝策略处理。

6、线程池的拒绝队列?
解答:
AbortPolicy(默认):直接抛出异常阻止系统正常运行。
CallerRunsPolicy:调用者运行机制。就是当多的任务,会被回退到启用线程池的那个线程。
DiscardOldestPolicy:抛弃阻塞队列中等待时间最久的那个,将新的加入阻塞队列中。
DiscardPolicy:直接丢弃任务,不做任何处理也不报错。

7、实际开发过程中,应该用JDK提供的哪个创建线程池的方法?
回答:一个都不用,自己改造线程池。改造线程池的方式也很简单,要做的调整只是在阻塞队列那里,因为系统提供的几种创建方式,阻塞队列的长度是无限长的,导致系统性能变差。

8、如何合理设置线程池的线程数?
回答:(1)如果是CPU密集型的话,先判断自己服务器的CPU核数,一般用CPU核数+1,尽量减少线程切换。(2)如果是IO密集型:一般用CPU核数/(1-0.80.9),0.80.9为阻塞系数。

9、线程池优势?
(1)重用存在的线程,减少线程创建消亡的开销,提高性能
(2)提高响应速度。当任务到达时,任务可以不需药等到线程创建就可以立即执行。
(3)提高线程的可管理性,可以统一分配,调优和监控。

线程池原理:
在这里插入图片描述
线程池的5中状态:
在这里插入图片描述在这里插入图片描述<hr style=" border:solid; width:100px; height:1px;" color=#000000 size=1">

Java运维知识

1、javaweb项目部署:云服务器上下载tomcat、mysql数据库、JDK运行环境等。然后把本地文件上传上去,把项目放到Tomcat的webapps文件夹下,服务器启动的时候会自动加载项目,就可以进行访问了。

2、Junit测试:Eclipse继承了Junit测试jar包,直接build path后,创建一个Junit 测试例子,然后自己修改测试方法,运行查看结果。

https://www.zhihu.com/question/20004877分布式与集群的区别。

在这里插入图片描述
使用分布式时候的RPC框架解释:【https://www.zhihu.com/question/25536695】
在这里插入图片描述


数据结构

1、各种数据结构的时间复杂度?
在这里插入图片描述
2、常见的排序算法时间复杂度?
在这里插入图片描述
算法个人感觉主要掌握几种重要算法编程
(1)快速排序
(2)归并排序
(3)冒泡排序
(4)希尔排序
如果还想了解其他关于算法的知识,后续我会在自己的博客里面更新一些算法知识专栏。

  • 1
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

\contentsline {chapter}{Contents}{2}{section*.1} {1}Java基础}{17}{chapter.1} {1.1}基本语法}{17}{section.1.1} {1.2}数字表达方式}{17}{section.1.2} {1.3}补码}{19}{section.1.3} {1.3.1}总结}{23}{subsection.1.3.1} {1.4}数据类型}{23}{section.1.4} {1.4.1}整数与浮点数}{23}{subsection.1.4.1} {1.4.1.1}浮点数原理}{24}{subsubsection.1.4.1.1} {1.4.2}格式化输出浮点数}{24}{subsection.1.4.2} {1.4.3}\texttt {char}}{24}{subsection.1.4.3} {1.4.4}转义字符}{25}{subsection.1.4.4} {1.4.5}Boolean 布尔值}{25}{subsection.1.4.5} {1.5}基本类型变量的初始值}{26}{section.1.5} {1.6}数据类型转换}{26}{section.1.6} {1.7}方法}{26}{section.1.7} {1.8}运算符}{27}{section.1.8} {1.8.1}自增运算}{28}{subsection.1.8.1} {1.8.1.1}Postincrement}{28}{subsubsection.1.8.1.1} {1.8.1.2}Preincrement}{28}{subsubsection.1.8.1.2} {1.8.1.3}复合赋值运算}{28}{subsubsection.1.8.1.3} {1.8.2}逻辑运算}{29}{subsection.1.8.2} {1.8.3}条件运算符}{29}{subsection.1.8.3} {1.8.4}移位运算符}{30}{subsection.1.8.4} {1.9}流程控制}{31}{section.1.9} {1.9.1}\texttt {if\ldots esle\ldots }}{31}{subsection.1.9.1} {1.9.2}\texttt {switch}}{31}{subsection.1.9.2} {1.9.3}\texttt {while}}{32}{subsection.1.9.3} {1.9.4}\texttt {for}}{32}{subsection.1.9.4} {1.9.5}foreach}{32}{subsection.1.9.5} {1.9.6}go-to}{33}{subsection.1.9.6} {1.9.7}\texttt {do-while}}{33}{subsection.1.9.7} {1.10}数组(array)}{34}{section.1.10} {1.10.1}数组变量的声明}{34}{subsection.1.10.1} {1.10.2}数组变量的初始化}{34}{subsection.1.10.2} {1.10.3}数组对象的引用}{35}{subsection.1.10.3} {1.10.4}数组对象的复制}{35}{subsection.1.10.4} {1.10.5}扩充数组对象长度}{36}{subsection.1.10.5} {1.10.6}Problems}{37}{subsection.1.10.6} {1.11}简单算法}{38}{section.1.11} {1.11.1}打乱算法}{38}{subsection.1.11.1} {1.11.2}排序算法}{38}{subsection.1.11.2} {1.11.2.1}选择排序}{38}{subsubsection.1.11.2.1} {1.11.2.2}冒泡排序}{39}{subsubsection.1.11.2.2} {1.11.2.3}插入排序}{40}{subsubsection.1.11.2.3} {1.11.3}递归调用}{41}{subsection.1.11.3} {1.12}Java API}{41}{section.1.12} {1.13}Linux命令}{41}{section.1.13} {1.13.1}基本查看、移动}{41}{subsection.1.13.1} {1.13.2}权限}{42}{subsection.1.13.2} {1.13.3}打包备份与恢复}{42}{subsection.1.13.3} {1
相关推荐
©️2020 CSDN 皮肤主题: 1024 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值