JavaSE

1.finally代码块一定会执行么?
否。
·主程序在进入try代码块前结束运行
·当一个线程在执行try语句时被打断或者被终止,例如出现System.init(0);
2.mysql中查找表机构用那个关键词
·DESC
3.如何强制垃圾回收期立即回收一个对象
·java中无法强制垃圾回收器立即执行
·System.gc()方法:告诉垃圾收集器开始回收,但jvm不保证立刻执行动作,
并且有可能会被拒绝
4.java线程:
wait()与sleep()的区别
·sleep属于Thread类,wait属于Object类
·调用sleep时,线程不会释放对象锁,调用wait则会释放
·sleep导致程序暂停指定的时间,但监控状态仍在持续,当时间到了会自动恢复
调用wait,线程会进入该对象的等待池,等待池中的线程不回去竞争对象锁。
5.协议转换:
·ARP:IP->MAC
·RARP:MAC->IP
·ARQ:数据链路层,自动重传请求
·ICMP:面向无连接的协议,用于传输出错控制报告信息
6.从通信协议来看,路由器是在那个层次上实现网络互连:
·集线器->物理层
·交换机->数据链路层
·路由器->网络层
7.在TCP/IP体系结构中,直接为ICMP提供服务协议的是IP
8.关于进程和线程:
·进程是系统分配资源的最小单位,使用独立内存空间(不论系统是否支持线程)
·线程是程序执行的最小单位,共享进程的空间
·系统级线程(内核线程)切换需要内核支持,用户级不需要内核支持
9.若某单处理器多进程系统中有多个就绪态进程,则下列关于处理机调度的叙述中,错误是?C
·在进程结束时能进行处理机调度
·创建新进程后能进行处理机调度
·在系统调用完成并返回用户态时能进行处理机调度
10.关于TCP协议的描述,以下错误的是?
·面向连接
·可靠交付
·报文头部长,传输开销大
11.关于C++程序运行时的函数地址:
·地址是否固定要看系统配置和编译选项,如果开启了地址随机化,那地址是每次都变得,
如果没开启那么地址每次都一样。
12.关于堆:
·堆是优先级队列的底层实现形式,有N个元素的优先级队列进行一次结构调整的时间复杂度为logN
·堆内存是一种动态分配的内存,其实际占用内存空间的大小随着程序的运行可以动态调整
·堆栈是一种线性数据结构,其特点是先进后出
·在c和java中,堆内存对于线程来说都是共享的。
13.关于select和epoll:
·epoll和select都是I/O多路复用的技术,都可以实现同时监听多个I/O事件的状态。
·epoll相比select效率更高,主要是基于其操作系统支持的I/O事件通知机制,而select是基于轮询机制。
·epoll支持水平触发(LT)和边沿触发(ET)两种模式
14.关于静态方法和静态变量:
.静态方法,静态变量在程序开始运行时就进行初始化;
非静态方法,非静态变量在创建该对象时才进行初始化。引用未初始化变量/方法即会报错。
.静态方法可以调用本类中的静态变量,不推荐调用本类中的成员方法(可能还未初始化)
.非静态方法可以调用静态变量和成员变量
15.B/S和C/S:
.C/S:client/server 客户端/服务器端
如qq,lol,优点:用户体验好 缺点:开发,安装,部署,维护很麻烦
.B/S:browser/server 浏览器/服务器端
只需要一个浏览器,用户通过不通风的网址(URL),客户访问不同的服务器端程序
优点:开发,安装部署,维护相对简单
缺点:如果应用过大,用户的体验可能 会受到影响;对硬件的要求过高
16.系统调用:
.定义:系统调用就是应用程序与系统内核之间的接口。通过系统调用访问系统资源。
.为什么要系统调用: 由于系统有限的资源可能被多个不同的应用程序同时访问可因此,如果不加以保护,
那么各个应用程序难免会产生冲突。所以一种解决方法是,不让应用程序直接访问系统的资源,所以
增加了一层中间接口,那就是系统调用
.调用的程序,运行在用户态,被调用的过程运行在内核
17.堆栈静态区:
.栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
.堆区(heap) — 一般由程序员分配释放 , 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
.全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量
在相邻的另一块区域(BSS)。 - 程序结束后由系统释放
.文字常量区 — 常量字符串就是放在这里的。 程序结束后由系统释放
.程序代码区— 存放函数体的二进制代码。
*18.mysql常用语句
*19.linux常用命令
20.final:final可用来修饰类,变量,方法:
.final修饰的类不能有子类,也不能被继承。
.final修饰的变量是一个常量,不能重新赋值。
.final修饰的引用类型变量,初始化后不能重新指向新的对象
.final修饰的方法不能重写
21.重载和重写:
.重载(Overload)是让类以统一的方式处理不同类型数据的一种手段,
实质表现就是多个具有不同的参数个数或者类型的同名函数(返回值不是重载的区分标准)
同一个动作作用在同一个对象上拥有不同的解释(编译时多态)
.重写(Override)是父类与子类之间的多态性,实质是对父类的函数进行重新定义,
如果在子类中定义某方法与其父类有相同的名称和参数则该方法被重写
同一个动作作用在不同的对象上拥有不同的解释(运行时多态)
22.ArrayList&LinkedList
.ArrayList底层为动态数组,查询快,增删慢
.LinkedList底层是双向链表,查询慢,增删快
23.输出一个某种编码的字符串
.new String(str.getBytes(“ISO-8859-1”),“GBK”)
24.String,StringBuffer,StringBuilder
.String为不可变对象,一旦创建值不可修改,对于已经存在的String对象的修改都是重新创建一个新的对象,然后把新的值保存进去。
String是final类,即不能被继承
.StringBuffer,StringBuilder是可变对象,当对它进行修改的时候不会像String那样重新建立对象。
它只能通过构造函数来建立
.StringBuffer支持并发操作,线性安全的,StringBuilder不支持并发操作,线性不安全的。
但其在单线程中的性能StringBuilde比StringBuffer高。
.底层实现StringBuffer其实就是比StringBuilder多了Synchronized修饰符,两者都基于char[]数组实现
25.Array和ArrayList
.ArrayList内部封装了一个object数组,其中index,sort等方法是在内部数组的基础上直接调用Array的对应方法
.ArrayList可以存储不同类型的对象,Array只能存储相同类型
.ArrayList长度可变,Array长度不可变
.对于值类型往ArrayList中添加修改元素会频繁的装箱拆箱,降低效率
.可能会越界,在多线程操作同一个ArrayList的时候,并发add()
26.Arrays.sort()实现原理
.当数组长度较小时,使用插入排序–>数据量小的时候.插入排序的常数代价非常低
.当数据量比较大时,当数组类型为基本数据类型会使用快排,对象类型使用归并排序(merge)
这是因为基本数据类型不需要考虑稳定性的因素,但对象类型需要排序的不止一个属性,需要考虑稳定性
27.值传递和引用传递:
.java中都是值传递
.值传递:指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
.引用传递:是指在调用函数时将实际参数的地址直接传递到函数中(的形参),那么在函数中对参数所进行的修改,将影响到实际参数
.如果参数类型是原始类型,那么传过来的就是这个参数的一个副本,也就是这个原始参数的值,如果在函数中改变了副本的值不会改变原始的值.
.如果参数类型是引用类型,那么传过来的就是这个引用参数的副本,这个副本存放的是参数的地址,如果在函数中没有改变这个副本的地址,而是改变了地址中的值,那么在函数内的改变会影响到传入的参数
如果在函数中new了新的对象,改变了地址,那么原对象的内容不受影响。
28.自动装箱与自动拆箱:
.装箱:自动将基本数据类型转换为包装类型
.拆箱:自动将包装类型转换为基本数据类型
.何时发生拆箱:基本数据类型和引用数据类型做运算时
.何时发生装箱:基本数据类型赋值给引用数据类型时
.包装类的“”在不遇到算数运算符的时候并不会自动拆箱
29.2进制的小数无法精确表达10进制的小数,计算机在计算10进制小数的过程中要先转换为2进制进行计算
这个过程出现了偏差(4.0-3.6=0.40000001)
30.一个十进制的数在内存中是怎么存的:
.进制补码形式存储
.最高位是符号位,正数为0,负数为1
.正数的补码是它的原码
.负数的补码是它的反码加1,在求反码时符号位不变,其他位取反
31.Lamda表达式的优缺点
.优点:1. 简洁。2. 非常容易并行计算。3. 可能代表未来的编程趋势。
.缺点:1. 若不用并行计算,很多时候计算速度没有比传统的 for 循环快。(并行计算有时需要预热才显示出效率优势)
2. 不容易调试。3. 若其他程序员没有学过 lambda 表达式,代码不容易让其他语言的程序员看懂。
32.java8新特性:
.Lambda 表达式 ? Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中。
.方法引用? 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
.默认方法? 默认方法就是一个在接口里面有了一个实现的方法。
.新工具? 新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。
.Stream API ?新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
.Date Time API ? 加强对日期与时间的处理。
.Optional 类 ? Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
.Nashorn, JavaScript 引擎 ? Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用
33."
“与equals比较:
.”=="比较引用对象时,是比较两个对象的内存地址来判断是不是同一个对象
比较基本类型时,是比较值的大小
.equals用来比较两个对象的内容是否相等
34.Object若不重写hashCode()的话,hashCode()如何计算出来的
.Object的hashCode方法是本地方法,也就是说是使用C或者C++语言实现的,该方法直接返回对象的内存地址
35.Hashmap为什么重写equals还要重写hashcode
.HashMap中,如果要比较key是否相等,要同时使用这两个函数!因为自定义的类的hashcode()方法继承于Object类,
其hashcode码为默认的内存地址,这样即便有相同含义的两个对象,比较也是不相等的。重写hashcode()方法可使得
具有相同含义的两个对象的hash码是相同的,但这还不够,hashmap底层是数组加链表的实现方式,在同一个hash码表示的位置上
可能有多个对象通过链表连接,此时还需要重写key对象的equals()方法,判断key的值是否相等。不重写equals时,系统调用
object类的equals方法,此方法是根据两个对象的内存地址判断,而两个对象的内存地址一定是不等的。

36.Map、HashMap和HashTable
.Map用于存放键值对,不允许键重复(重复则覆盖)
.HashMap根据键的hashcode值存储数据,有很快的访问速度,遍历时取得数据顺序随机,
最多只允许一个键为null,线程不安全,任意时刻可能有多个线程写hashmap,
key可以重复,value不允许重复
.HashTable不允许键或值为null,线程安全,任意时刻只能有一个线程写hashtable,故写入速度较慢
.底层实现:HashMap最底层是数组实现,数组中每个由hashcode确定的位置由链表连接,
当链表的长度超过8时,并且数组的长度超过64(否则会认为是数组太小导致的hash冲突)才会采用红黑树,提高map的效率;
37.Synchronized和lock:
.synchronized是Java的关键字,属于JVM层面,底层由一对monitorenter和monitorexit指令实现的
Lock是一个接口,是API层面的锁
.synchronized不需要用户手动释放锁,当synchronized代码块执行完成后,系统会自动让线程释放对锁的占用
Lock需要用户手动释放锁,若没有手动释放可能导致死锁现象。
.synchronized不可中断,除非抛出异常或者正常运行完成
Lock可中断
.lock能完成synchronized所实现的所有功能
.死锁:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止
.死锁产生的四个必要条件:
互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用
不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放
请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有
循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环
*如何写一个死锁
.避免死锁的一种方法:
指定获取锁的顺序,并强制线程按照指定的顺序获取锁。因此,如果所有的线程都是以同样的顺序加锁和释放锁,
就不会出现死锁了
*银行家算法:当一个进程申请使用资源的时候,银行家算法通过先试探分配给该进程资源,然后通过安全性算法
判断分配后的系统是否处于安全状态,若不安全则试探分配作废,让该进程继续等待
38.volatile关键字:
.volatile关键字是用来保障有序性和可见性。
.有序性:在本线程内观察,所有操作都是有序的volatile可以禁止指令重排序优化,通过插入内存屏障,
指令排序时不能把后面的指令冲排序到内存屏障之前的位置。
.可见性:当一个线程修改了某一变量的值,新值对于其他线程是立即可知的,各个工作内存中加了volatile的变量执行前会刷新保持一致。
加了volatile关键字的的汇编代码,会多出一个lock前缀指令,锁住总线。后提出缓存一致性协议,保证多核数据不一致问题。
.原子性:volatile没有保证原子性的功能。基本数据的访问读写都是具有原子性的,在需要大范围的原子性保证时,
可使用synchronized关键字,synchronized块之间的操作具备原子性。
39.Syncronized锁:
.在代码块上面加上Syncronized该代码块就称为同步代码块.在方法上面加上Syncronized该方法就称为同步函数
对于static方法,同步锁就是我们使用当前方法所在类的字节码对象,即类锁
对于非static方法,同步锁就是this,对象锁。
40.Query接口的list方法和iterate方法有什么区别:
.list()方法无法利用一级缓存和二级缓存(对缓存只写不读),它只能在开启查询缓存的前提下使用查询缓存;
iterate()方法可以充分利用缓存,如果目标数据只读或者读取频繁,使用iterate()方法可以减少性能开销
. list()方法不会引起N+1查询问题,而iterate()方法可能引起N+1查询问题
41.面对对象四大特征:
.抽象:抽象是将一类对象的共同特征总结出来构造类的过程包括数据抽象和行为抽象两方面,
抽象只关注对象的哪些属性和行为,并不关注这此行为的细节是什么
.封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口
面向对象的本质就是将现实世界描绘成一系列完全自治,封闭的对象,可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口
.继承:继承是从已有类得到继承信息创建新类的过程,继承让变化中的软件系统有了一定的延续性
.多态:多态性是指允许相同或不同子类型的对象对同一消息作出不同响应
42.面向对象的"六原则一法则":
.单一职责原则:一个类只做它该做的事情
.开闭原则:软件实体应当对扩展开放,对修改关闭
.依赖倒转原则:面向接口编程
.里氏替换原则:任何时候都可以用子类型替换掉父类型
.接口隔离原则:接口要小而专,绝不能大而全
.合成聚合复用原则:优先使用聚合或合成关系复用代码
.迪米特法则:一个对象应当对其他对象有尽可能少的了解(低耦合)
*43.反射
—>见92
*44.内部类
.内部类可以访问外部类的成员,包括私有;外部类要访问内部类成员则必须创建对象
.Static nested class(嵌套类)是将内部类声明为static(静态内部类).
1>要创建嵌套类的对象,并不需要其外围类的对象;2>不能从嵌套类的对象中访问非静态的外围类的对象。
45.Java的接口和C++的虚类的相同和不同处
.一个子类只能继承一个抽象类(虚类),java没有多继承但能实现多个接口达到类似效果;
.接口里面的属性在默认状态下面都是public static,所有方法默认情况下是public
46.创建进程过程:
.1,申请空白PCB(进程控制块);
.2,为新进程分派资源;
.3,初始化PCB;
.4,将新进程插入就绪队列
47.抽象类和接口的区别:
.含有abstract修饰符的class即为抽象类,抽象类可以有构造方法,接口没有构造方法
.抽象类中可以含有普通成员变量,接口中没有成员变量
.抽象类可以含有非抽象的普通方法,接口所有方法必须抽象
.抽象类中可以有静态方法,接口中不包含静态方法
.一个类可以实现多个接口,但只能实现一个抽象类
.如果一个类继承了抽象类但没有实现其全部方法,那么此类也是抽象类
48.final, finally, finalize
.final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承
.finally是异常处理语句结构的一部分,表示总是执行
.finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,
可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等
49.Comparable和Comparator接口的作用以及它们的区别:
.在给集合排序时,使用Collections.sort()方法,如果要想给自定义person数组牌排序,则需要在
类中实现Comparable接口并重写CompareTo()方法。–>内部比较器
.Comparator:外部比较器用于对那些没有实现Comparable接口或者对已经实现的Comparable中的排序规则不满意进行排序.
无需改变类的结构,更加灵活,需重写compara方法。
.方法返回-1,0,1分别代表小于、等于、大于
50.请解释extends 和super 泛型限定符-上界不存下界不取
.extends上限通配符,用来限制类型的上限,只能传入本类和子类,add方法受阻,可以从一个数据类型里获取数据
< ? extends Object>
.super下限通配符,用来限制类型的下限,只能传入本类和父类,get方法受阻,可以把对象写入一个数据结构中
< ? super Object>
51.什么是泛型
.泛型,即“参数化类型”,类型由原来的具体的类型–>参数化,类似于方法中的变量参数,此时类型也定义成参数形式
泛型只在编译期起作用,在编译过程中检验了泛型的正确后,会将泛型的相关信息擦除,泛型信息不会进入运行阶段
52.jvm虚拟内存分布:
.程序计数器:程序控制流指示器,存在一些跳转指令
.虚拟机栈:jvm执行java代码所使用的栈
.本地方法栈:jvm使用本地方法(Native)使用的栈
.方法区:存放被虚拟机加载的类型信息、常量、静态变量等,可以理解为class文件在内存中存放的位置
.java堆:存放对象实例
…>其中方法区和堆是所有线程共享的区域
53.方法区:
.静态常量区:存在类和接口的全限定名等
.运行时常量区:用于存放编译期生成的各种字面量和符号引用,这部分内容将会在类加载后存放在方法区的常量区
当java虚拟机遇到一条new字节码指令,首先会检查这个指令的参数能否在常量池中定位到一个类的符号引用,如果没有就会执行相关的类加载过程。
54.双亲委派模型:
.当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,
递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类
.作用:
防止重复加载同一个.class
保证核心.class不能被篡改
55.类文件(.class):
.所谓 Java 类文件,就是通常用 javac 编译器产生的 .class 文件。这些文件具有严格定义的格式
.class文件是一组以8个字节为基础单位的二进制流
.不同语言可以通过相应的编译器编译为.class文件,此时java虚拟机就可以执行,这构成了java语言平台无关性的基础
.java类文件大概包括:magic number(分辨是否为java文件)、Version、Super Class(指向表示父类全限定名称的字符串常量的指针)等
*56.类加载机制:
.类加载是指java虚拟机把类的class文件加载至内存,并对里面数据进行校验、转换和初始化等,最终形成可以直接被虚拟机使用的java
类型。
.类加载的过程:加载–>验证–>准备–>初始化–>卸载
加载的类会生成java.lang.Class对象
.类加载的时机
使用new关键字实例化对象
对类进行反射调用
虚拟机启动,先初始化main()
.类加载器:类加载器是一个用来加载类文件的类,类加载器负责加载文件系统、网络或其他来源的类文件
57.虚拟机:
.虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机有自己完善的硬体架构,如处理器、堆栈、寄存器等,
还具有相应的指令系统。JVM屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行
58.List、Set:
.List允许重复,Set不允许数据重复
.HashSet基于HashMap实现,更像是对HashMap做了一次“封装”,而且只使用了HashMap的key来实现各种特性
HashSet不允许重复(HashMap的key不允许重复,如果出现重复就覆盖)
59.Collection 和 Collections:
.Collection是一个集合类的上级接口,继承他常用的接口是set和list
.Collections是针对集合的一个工具类,提供一系列静态方法,如排序、搜索等。
类似Arrays工具类
60.迭代器:
.可迭代是Java集合框架下的所有集合类的一种共性,也就是把集合中的所有元素遍历一遍。
迭代的过程需要依赖一个迭代器对象,他的含义是:提供一种方法访问一个容器对象中各个元素,
而又不需暴露该对象的内部细节
.iterator提供了统一遍历操作集合元素的统一接口, Collection接口实现Iterable接口,
每个集合都通过实现Iterable接口中iterator()方法返回Iterator接口的实例, 然后对集合的元素进行迭代操作
.需要注意的是:在迭代元素的时候不能通过集合的方法删除元素, 否则会抛出ConcurrentModificationException 异常.
但是可以通过Iterator接口中的remove()方法进行删除.
.迭代器包含的方法:
hasNext() next() remove()
61.快速失败(fail-fast)和安全失败(fail-safe)
.快速失败(fail-fast):
在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行了修改(增加、删除、修改),则会抛出Concurrent Modification Exception
java.util包下的集合类都是快速失败的,不能在多线程下发生并发修改(迭代过程中被修改)
.安全失败(fail-safe):
在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。
java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改
62.Serializable接口
.一个类只有实现了Serializable接口,它的对象才能被序列化
.什么是序列化?
将对象的状态信息转换为可以存储或传输的形式的过程
.什么情况下需要序列化?
当我们需要把对象的状态信息通过网络进行传输,或者需要将对象的状态信息持久化,以便将来使用时都需要把对象进行序列化
.序列化的作用
实现 Serializable接口的作用就是可以把对象存到字节流,然后可以恢复。所以你想如果你的对象没有序列化,怎么才能进行网络传输呢?
要网络传输就得转为字节流,所以在分布式应用中,你就得实现序列化。如果你不需要分布式应用,那就没必要实现实现序列化
63.TreeMap的底层实现
.红黑树
64.HashMap的容量为什么是2的n次幂
.2^n是为了让散列更加均匀,减少hash碰撞,例如出现极端情况都散列在数组中的一个下标
.hashmap的扩容:
hashmap默认容量是16,负载因子默认是0.75,就是是说当元素个数超过16
0.75=12时,hashmap就会扩大一倍。
默认加载因子是 0.75, 这是在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本,
包括 get 和 put 操作)
65.java线程的实现:
.内核线程实现–>需要消耗内核资源
.用户线程实现–>没有系统内核的支援,所有线程都需要用户自己程序处理,较为复杂,较少使用
.两者混合
66.java线程调度:
.线程调度:系统为线程分配处理器使用权的过程
.协同式:线程使用的时间由自己控制,线程执行完毕后,要主动通知系统去执行下一个线程
缺点:线程执行时间不可控,某一线程出问题不告诉系统切换线程,那么线程就会一直被阻塞
.抢占式:每个线程执行时间由系统分配,线程切换不由线程本身决定
java使用的是抢占式线程调度
67.线程与线程优先级:
.优先级具有继承性
.线程优先级高的并不一定在低之前执行。(我们无法准确判断)
原因:1.java线程是映射到系统原生线程上的,这两者的映射并不是一一对应
2.优先级可能会被系统自行改变
.java中优先级范围1-10,默认为5,10最高–>t1.setPriority()
68.java六种线程的状态
.新建(new):创建后尚未启动的线程处于此状态
.运行(runnable):处于此状态可能正在运行,也可能正在等待操作系统为他执行分配时间
.无限等待(waiting):进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒
以下方法会让线程进入无线等待:
无参数的object::wait();无参数的thread::join()
.限期等待(timed Waiting):在一定时间后由系统自动唤醒
进入限期等待的方法:
thread::sleep();设置了timeout参数的object::wait();设置timeout参数的thread::join()
.阻塞(blocked):当一个线程试图获取一个锁对象,而该对象被其他的线程持有,则该线程进入Blocked状态
.结束(terminated):已终止线程。
-多线程五种状态对比:
.新建状态
.就绪状态
start()方法执行后,线程处于此状态
.运行状态
获得CPU时间后,进入运行状态,真正执行run()方法
.阻塞状态
.死亡状态
有两种原因导致线程死亡
1.run()正常退出
2.一个未捕获的异常终止了run()而使线程猝死
69.线程池:
.线程池就是首先创建一些线程,它们的集合称为线程池。使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,
程序将一个任务传给线程池,线程池就会启动一条线程来执行这个任务,执行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务
.优点:
1.降低资源消耗
2.提高响应速度
3.提高线程的可管理性,使用线程池可以统一监管
79.同步和异步:
.同步:就是调用某个东西是,调用方得等待这个调用返回结果才能继续往后执行.
即阻塞式操作
.异步:调用方不会理解得到结果,而是在调用发出后调用者可用继续执行后续操作
非阻塞时操作
80.线程同步和线程调度的方法:
.object::wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁
.thread::join():让其他线程变为等待
.thread::sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理InterruptedException异常,但对象锁依然保持
.object::notity():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,
而是由JVM确定唤醒哪个线程,而且与优先级无关
.object::notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,
只有获得锁的线程才能进入就绪状态
.thread::yield():暂停当前正在执行的线程,并执行其他线程(但可能没有效果)
81.线程的sleep()方法和yield()方法:
.sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;
yield()方法只会给相同优先级或更高优先级的线程以运行的机会
.线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态
82.生产者和消费者模式:
.生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据。
83.多线程中的 start() 和 run():
.Thread类的 start()方法来启动一个线程,这时此线程处于就绪(可运行)状态
.Thread类的run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程
84.多线程创建的三种方式:
.继承Thread类
.实现Runnable接口
.匿名内部类
84.实现Runnable接口比继承Thread类所具有的优势:
.可以避免java中的单继承的局限性。
.增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和数据独立
.线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类
85.用户线程和守护线程:
.用户线程是指用户自定义创建的线程,主线程停止,用户线程不会停止
.守护线程当进程不存在或主线程停止,守护线程也会被停止
86.线程停止的方法:
.设置退出标志,使线程正常退出
.使用interrupt中断线程
87.jvm内存结构、java对象模型和java内存模型:
.jvm内存结构:描述的是Java程序执行过程中,由JVM管理的不同数据区域。各个区域有其特定的功能
程序计数器、虚拟机栈、本地方法栈、java堆、方法区
.Java对象模型:Java是一种面向对象的语言,而Java对象在JVM中的存储也是有一定的结构的。而这个关于Java对象自身的存储模型称之为Java对象模型。
栈、方法区和堆各存放哪些数据
.java内存模型:就是一种符合内存模型规范的,屏蔽了各种硬件和操作系统的访问差异的,
保证了Java程序在各种平台下对内存的访问都能保证效果一致的机制及规范
每条线程的本地内存和主内存的关系(并发编程)
88.解决可见性的一种方法:
.synchronized锁
线程解锁前(退出同步代码块时):必须把自己工作内存中共享变量的最新值刷新到主内存中
线程加锁时(进入同步代码块时):将清空本地内存中共享变量的值,从而使用共享变量时
需要从主内存中重新读取最新的值(加锁与解锁是同一把锁)
89.线程安全的实现:
.互斥同步是一种最常见也是最主要的并发正确性保障手段,在java里最基本的互斥同步手段就是
synchronized关键字
.被synchronized修饰的同步块在持有锁的线程释放锁之前,会无条件的阻塞后面其他线程的进入
90.锁优化:
.锁主要存在四中状态,依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态.
.锁可以升级但不可以降级
.锁优化的方法:
.自旋锁:所谓自旋锁,就是让该线程等待一段时间,不会被立即挂起,看持有锁的线程是否会很快释放锁。
怎么等待呢?执行一段无意义的循环即可。
.锁消除:在有些情况下,JVM检测到不可能存在共享数据竞争,这是JVM会对这些同步锁进行锁消除
.锁粗化:将多个连续的加锁、解锁操作连接在一起,扩展成一个范围更大的锁
.偏向锁
.轻量级锁:引入轻量级锁的主要目的是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗
91.JDK/JRE
.JDK:java程序语言设计、java虚拟机、java类库这三部分统称为jdk,jdk是用于支持java程序开发的
最小系统
.JRE:是支持java程序运行的标准环境
92.反射:
.JAVA语言编译之后会生成一个.class文件,反射就是通过字节码文件找到某一个类、类中的方法以及属性等。
反射的实现主要借助以下四个类:Class:类的对象,Constructor:类的构造方法,Field:类中的属性对象,Method:类中的方法对象
.作用:反射机制指的是程序在运行时能够获取自身的信息
.好处:1.可以在程序运行过程中,操作这些对象
2.可以解耦,提高程序可扩展性
.获取class对象的方式(对应java代码的三个阶段):
1.Class.forName(“全类名”):将字节码文件加载进内存,返回class对象–>源代码阶段
2.类名.class:通过类名的属性获取class -->类对象阶段(类已经通过类加载器加载至内存)
3.对象.getclass():getclass()在object定义–>运行时阶段
.一个结论:同一个字节码文件在一次程序运行中只会被加载一次,不论通过哪一种方式获得的都是
同一个class对象
.方法:
personclass.getDeclaredFields()–>获取所有成员的变量,包括private
personclass.getFields()–>获取public修饰的变量
personclass.getMethod(method name,args.class)
method.invoke();–>执行通过反射获得的方法
.暴力反射:
field.setAccessible(true);可以获取私有属性的值
93.jvm加载class文件的原理
.jvm中类的加载是由classloader和他的子类实现的
.java类的加载是动态的,并不会一次性将所有类加载,而是保证了程序运行的基础类,其他类则在需要时在加载。
94.哪些可以作为GC Roots对象:
.虚拟机栈中的引用对象
.方法区中的类静态属性引用对象
.方法区中常量引用对象
.本地方法栈JNI引用对象(即通常所说的native方法);
95.GC如何判断对象是否需要被回收:
.目前主流的商用语言都基于可达性分析来判断对象是否存活。
.可达性分析算法:通过GC Roots对象为起点,通过引用关系向下搜索,搜索过得路程成为引用链,如果某个对象
到GC Roots之间没有任何引用链相连,则证明该对象不会再被使用。(并不是非回收不可)
.程序员可以手动执行System.gc()通知GC执行,但java语言规范并不保证gc一定执行
.垃圾回收主要发生在堆区域
96.java内存泄漏:
.原因:当一个对象已经不需要再使用本该被回收时,另外一个正在使用的对象持有它的引用从而导致它不能被回收,
这导致本该被回收的对象不能被回收而停留在堆内存中,这就产生了内存泄漏
(不再使用的对象没有被回收)
.有两类主要的Java内存泄漏:
1.不再需要的对象引用
2.未释放的系统资源
97.Error和Exception:
.Error和Exception都继承了Throwable类,只有Throwable类的实例才能被抛出或者捕获
.Exception和Error体现了Java平台设计者对不同异常情况的分类:
1.Exception和Error体现了Java平台设计者对不同异常情况的分类
2.Error是指正常情况下,不大可能出现的情况,绝大部分的Error都会导致程序处于非正常的、不可恢复的状态
98. io和nio:
.NIO即new io,在jdk1.4引入
.NIO和IO区别:
.面向流和面向缓冲:
>IO是面向流的,NIO面向缓冲区。
Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方
Java NIO的数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性
>阻塞与非阻塞io
Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write() 时,该线程被阻塞,直到有一些数据被读取,
或数据完全写入。该线程在此期间不能再干任何事情了
Java NIO是非阻塞的
99.垃圾回收算法:
.一般用<可达性分析算法>判断对象是否存活。
.垃圾回收算法:
.标记-清除:算法标记需要回收的对象,然后清除,会造成许多内存碎片
.标记-整理:与标记-清除算法类似,但是在标记之后,会将活的对象移向另一边,然后清除边界之外的垃圾对象—适用于老年代
.标记-复制:将内存分为两块,只使用一块,进行垃圾回收时,先将存活的对象复制到另一块,然后清空之前的区域—使用与年轻代
.分代收集:算法将对象分为年轻代和老年代。年轻代每次需回收较多对象,采用标记复制算法。老年代每次回收较少对象,采用标记整理法
100.垃圾回收器:
.CMS
.以获取最短回收停顿时间为目标的收集器,常用在b/s系统它是一种并发收集器,采用的是标记-清除算法
.场景 需要更快的响应,不希望有长时间的停顿,同时cpu资源比较丰富
.垃圾回收步骤:
.初始标记 (Stop the World 事件 CPU 停顿, 很短) 初始标记仅标记一下 GC Roots 能直接关联到的对象,速度很快;
.并发标记 (收集垃圾跟用户线程一起执行) 并发标记过程就是进行 GC Roots 查找的过程;
.重新标记 (Stop the World 事件 CPU 停顿,比初始标记稍微长,远比并发标记短) 修正由于并发标记时应用运行产生变化的标记。
.并发清理,标记清除算法
101.classpath:
.在编译生成的项目下的bulid/classes/ 下具有的文件都是classpath 路径下的文件
.规则:找到当前资源和目标资源之间的相对位置关系
* ./:当前目录
* …/:后退一级目录
102.动态代理:
.静态代理:
.由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成
.动态代理:
.代理类在程序运行时创建的代理方式被成为动态代理
.动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法
.动态代理的实现依靠Proxy类和一个InvocationHandler接口
.详见https://www.cnblogs.com/gonjan-blog/p/6685611.html
103.二叉查找树:
.左子树上所有结点的值均小于它的根结点的值
.右子树上所有结点的值均大于或等于它的根结点的值
.左、右子树也分别为二叉排序树
103.红黑树:
.红黑树是一种自平衡的二叉查找树
.性质:
.每个节点增加了一个存储位记录节点的颜色(黑色或者红色)
.根节点是黑色的
.如果一个节点是红色,那么其子节点比为黑色,不允许红连红
.对于每个节点,从该节点到其后代叶节点的简单路径上,均包含相同数目的黑色节点
.自平衡调整:
.旋转
.变色
.优势:
.红黑树的 查询性能略微逊色于AVL树,因为他比avl树会稍微不平衡最多一层,
也就是说红黑树的查询性能只比相同内容的avl树最多多一次比较,但是,<<红黑树在插入和删除上完爆avl树>>,
avl树每次插入删除会进行大量的平衡度计算,而红黑树为了维持红黑性质所做的红黑变换和旋转的开销,
相较于avl树为了维持平衡的 开销要小得多
.应用场景:
TreeMap、TreeSet、HashMap
104.AVL树:
.本身首先是一棵二叉查找树
.带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1。
也就是说,AVL树,本质上是带了平衡功能的二叉查找树(二叉排序树,二叉搜索树)
105.B树:
.B树启发于二叉查找树,二叉查找树的特点是每个非叶节点都只有两个孩子节点。然而这种做法会导致当数据量非常大时,二叉查找树的深度过深,
B树查找路径不止两条,不止两个孩子节点
.优势:
当数据量非常大时,二叉查找树的深度过深,搜索算法自根节点向下搜索时,需要访问的节点也就变的相当多。
如果这些节点存储在外存储器中,每访问一个节点,相当于就是进行了一次I/O操作,随着树高度的增加,频繁的I/O操作一定会降低查询的效率
.应用:
广泛应用在数据库中
106.B+树;
.B+树是B树的一种变形,它更适合实际应用中操作系统的文件索引和数据库索引
B+Tree 非叶子节点不存放数据
叶子节点存储关键字和数据,非叶子节点的关键字也会沉到叶子节点,并且排序
.B+树相比于B树,在文件系统,数据库系统当中,更有优势,原因如下:
.B+树的磁盘读写代价更低:
B+树的内部结点并没有指向关键字具体信息的指针。因此其内部结点相对B树更小。如果把所有同一内部结点的关键字存放在同一盘块中,
那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说I/O读写次数也就降低了。
.B+树的查询效率更加稳定
B+树非叶子节点不存放数据。所以任何关键字的查找必须走一条从根结点到叶子结点的路。
所有关键字查询的路径长度相同,导致每一个数据的查询效率相当
.B+树更有利于对数据库的扫描
B+树只需要遍历叶子节点就可以解决对全部关键字信息的扫描
107.Mysql索引结构:
.innoDB:
.主键索引:主键索引的叶子结点存放的是key值和数据,叶子结点载入内存时,数据一起载入,找到叶子结点的key,就找到了数据。
innoDB就是主键索引
.辅助索引:是将数据和索引分开,查找时需要先查找到索引,然后通过索引回表找到相应的数据

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值