java面试题总结2

16.想让所有线程都等到一个时刻同时执行有哪些方法
CountDownLatch:CountDownLatch首先我们在构造函数当中传入了一个标志值,然后在需要阻塞的地方调用await(),直到其他线程把countDown减少完。这个是不可重用的。
CyclicBarrier:和他的名字一样栅栏,我们对他的构造函数传入一个栅栏值,在需要阻塞的地方调用await的时候我们就对其基础值加一,直到等于栅栏值。调用CylicBarrier的reset方法可以对他进行重置。
Semaphore信号量:Semaphore可以同时控制访问的线程个数,如果需要这个资源我们会acquire()以阻塞的方式去请求,如果没有可用的信号量,就等待,release释放信号量,这个机制有点类似于锁。
在jdk1.7中提供了一个同步器Phaser,作用和countdownLatch,CyclicBarrier类似,但PHaser的使用方式更为灵活。使用register注册方法递增计数器,使用arriveAndDeregister()方法来递减计数器,使用arriveAndAwaitAdvane()方法阻塞线程,当计数器归0唤醒。
17.volatile的作用
第一:volatile是Java虚拟机提供的最轻量级的同步机制,使变量对所有的线程可见,保证了可见性,但是并不能保证它的原子性。
第二个:禁止指令重排序优化。普通变量仅仅保证在该方法所有依赖赋值结果的地方都能获取到正确的结果,而不能保证变量赋值操作的顺序与程序代码中的执行一样。从硬件的方面来说,并不是指令任意重拍,他只是把多条指令不安程序规定顺序分发给电路处理单元,比如说23+5 23之间是有依赖,5就可以排到他们前面。volatile会帮助我们加入内存屏障防止重排序。volatile读操作性能消耗与普通变量几乎没区别,写操作会慢一些,因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。
注意:对于volatile修饰的变量,jvm只是保证从主内存加载到线程的工作的内存是最新的

18.谈一谈java内存模型
(1)java虚拟机规范试图定义一种JAVA内存模型来屏蔽掉各种硬件和操作系统的内存访问的差异。
(2)java内存模型的主要目标是定义程序中各个变量的访问规则,这里的变量不包含局部变量和方法参数,而是指的是实例字段、静态字段、和构成数组对象的元素。
(3)java内存模型规定了所有的变量都存储在主内存中,而线程内的局部变量在自己的工作内存中,并且还有被该线程使用到的变量的主内存 的副本拷贝,线程对变量的操作(读取、赋值)都在工作内存中进行,不能直接读写主内存的变量,不同的线程无法直接访问对方工作内存的变量,线程键的变量值的传递需要通过主内存来完成,在内存模型中比较重要的就是工作线程和主内存的交互。

19.内存之间的交互:
java内存模型定义的操作:
Lock (锁定)
Unlock(解锁)
Read(读取)
Load(载入)
Use(使用)
Assign(赋值)
Store(存储)
Write(写入)
变量从主内存到工作内存:按照顺序执行read load操作
变量从工作内存到主内存:按照顺序执行Store write操作
重排序:包括编译器优化重排序、指令级并行重排序、内存系统重排序

20.什么时候使用LinkedList?
首先分写LinkedList和ArrayList的不同,在经常插入和删除的时候,在实现栈和队列的时候,不适合随机查找元素。

21.Object有哪些方法(九大方法),clone是深复制还是浅复制,finalize一般在什么时候使用:
wait,notify,notifyall,clone,getclass,toString,equals,hashcode,finalize。

  1. Clone()方法
    private保护方法,实现对象的浅复制,只有类实现了Clonable接口才可以调用该方法,否则抛出CloneNotSupportException。clone是浅复制,复制完成后其中的变量引用还是和以前的一样,如果要实现深复制需要我们把所有的变量引用都递归复制一次,然后再赋值。(或者额使用序列化,也可以实现深拷贝)如果我们要自己实现clone()方法必须要实现克隆接口clonable。

  2. Equals()方法:在object中与==是一样的,子类一般需要重写该方法

  3. hashCode()方法
    该方法用于哈希查找,重写了equals方法一般都要重写hashcode方法,这个方法在一些具有哈希功能的collection中使用

  4. getClass()方法:final方法,获得运行时的类型

  5. Wait()方法

使得当前的线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。Wait方法会一直等待,直到获得锁(到了睡眠的时间间隔也会唤醒自己)或者被中断掉。
调用该方法,当前的线程会进入到睡眠的状态,直到调用该对象的notify方法、notifyAll方法、调用interrupt中断该线程,时间间隔到了。

  1. Notify()方法:唤醒在该对象上的等待的某个线程

  2. notifyAll()方法:唤醒在该对象上的等待到所有的线程

  3. toString()方法:把对象转换成string类型进行输出

  4. finalize()方法

finalize在我们垃圾回收器回收这个对象的时候工作,可以做一些后续的工作,即进行一些必要的清理和清除的工作,比如说关闭流。当然我们也可以在这个里面对我们即将被回收的对象逃出回收。这里需要注意的是系统只会调用一次finalize()方法。但是一般我们不推荐使用这个方法,因为这个方法是为了对开始C和C++程序员的一种妥协,因为C中有析构函数,这个方法运行代价高,不确定大,我们还是会推荐使用try{}finally,他做的方法try{}finally都可以做。

23.如何管理线程(主要介绍各种线程池的实现)
使用线程池来管理线程
在Java中实现多种线程池
我们使用executors工厂产生我们的线程池,当线程池达到负载的时候会在我们线程池管理的Runnable阻塞队列中等待,不会像线程那样竞争CPU
第一种 newFixedThreadPool,和它的名字一样这是一个固定线程池,我们可以设置基本大小也就是我们没有任何任务执行的时候的大小,最大大小,只有在工作队列满了才能达到最大大小。
第二种 newCachedThreadPool这种线程池把大小设置为Integer.MAX_VALUE,基本大小设置为0,空闲超时设置1分钟,这种线程池可以无限扩展,并且当需求降低时会自动收缩。
第三种 newSingleThreadPool这种线程池把基本大小设置为1,最大大小都设置为1,只允许同一时刻一个线程。
固定线程池和单线程池固定默认使用的是阻塞队列无界的LinkedBlockingQueue,在这个阻塞队列中可以无限增长。但是对于我们的newCachedThreadPool来说他的线程池是无限大的,不需要阻塞等待,我们这里使用的是SynchronousQueue来避免排队,其实这个东西不是一个队列,是直接在线程之间进行移交,当线程池的大小小于所需要的时候,要么创建一个要么拒绝一个。我们一般在使用的时候可以扩展,使用使用信号量来控制提交速率。

24.如何让线程A等待线程B结束

使用join方法可以等待A线程结束,或者单线程池中 阻塞队列的方式让A先获得单线程池的线程,然后B一直阻塞,知道A释放自己的线程。
如何优化jvm参数:首先设置堆的大小,一般设置xmx和xms大小相同,如果老年代容易溢出可以扩充老年代,也要适当的调整永久代大小,选择自己合适的收集器,调整新生代对象年龄阀值等。

25.什么是守护线程
线程会分为两种:
普通线程和守护线程。在JVM启动时创建的所有线程中,除了主线程其他都是守护线程,比如说垃圾回收器就是守护线程,当普通线程全部退出的时候守护线程也会退出,我们自己也可以手动设置手动线程在线程启动之前,但是我们应该尽可能少使用守护线程,因为我们很少有操作可以在不进行清理就可以安全地抛弃,比如说I/O操作。

26.TCP如何控制拥塞
拥塞控制就是防止过多的数据注入网络中,这样可以使网络中的路由器或链路不致过载。
发送方维持一个叫做拥塞窗口cwnd(congestion window)的状态变量。
为了防止cwnd增长过大引起网络拥塞,还需设置一个慢开始门限ssthresh状态变量。ssthresh的用法如下:
当cwnd 当cwnd>ssthresh时,改用拥塞避免算法。也就是加法算法
当cwnd=ssthresh时,慢开始与拥塞避免算法任意。
当出现拥塞的时候就把心的门限值设为此时窗口大小的一般,窗口大小设置为1,再重新执行上面的步骤。
当收到连续三个重传的时候这就需要快重传和快恢复了,当收到连续三个重传 这个时候发送方就要重传自己的信息,然后门限减半但是这个时候并不是网络阻塞,窗口只会减半执行拥塞避免算法。
28.ThreadLoacl?
我们使用ThreadLocal为每个使用该类型的变量提供了一个独立的副本,具体的实现是在每个线程中保存了一个ThreadLocalMap,这个ThreadLoaclMap会在我们第一次使用ThreadLoal中的set方法创建出来,set方法就是保存在ThreadLocalMap中,该变量为key,值为value,get方法也从这个HashMap中找。
29.OSI网络模型?
网卡在哪一层(物理层)
交换机在哪一层(链路层)
路由器在哪一层(网络层)
传输TCP
会话 SQL
表示 IMG
html在应用层

30.HTTP1.0和Http1.1区别?
1.0默认是多次tcp连接多次请求,然后增加了keep alive功能,但是必须在request Header手动增加Connection:keepalive
1.1是一次tcp连接多次请求,新的persistence功能

31.POST和GET方法的区别?
长的说:对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
也就是说,GET只需要汽车跑一趟就把货送到了,而POST得跑两趟,第一趟,先去和服务器打个招呼“嗨,我等下要送一批货来,你们打开门迎接我”,然后再回头把货送过去。
因为POST需要两步,时间上消耗的要多一点,看起来GET比POST更有效。因此Yahoo团队有推荐用GET替换POST来优化网站性能。但这是一个坑!跳入需谨慎。为什么?
GET与POST都有自己的语义,不能随便混用。
据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。
并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。
get是从服务器上获取数据,post是向服务器传送数据。
get是通过URL来传递数据,POST是通过表单传递,因此get数据限制在1024k,而POST没有限制
在java服务器端get是通过request.qureySting post通过request.getParameterNames和reque.getParameterValue
get是安全的,幂等的 POST即不安全又不幂等(多次操作和一次操作一样)
在rest中设计的话,一般get用来查询数据,POST用来添加数据,PUT用来更新数据,Delete用来删除数据

32.filter执行顺序?
多个filter的执行顺序是web.xml中的配置顺序

33.影响SQL执行效率的因素?

  1. is null和is not null
  2. 通配符的like
  3. order by
  4. not
  5. in和exists

34.GBK和UTF-8的区别
GBK包含全部中文字符; UTF-8则包含全世界所有国家需要用到的字符。GBK的文字编码是双字节来表示的,即不论中、英文字符均使用双字节来表示,只不过为区分中文,将其最高位都定成1。
至于UTF-8编码则是用以解决国际上字符的一种多字节编码,它对英文使用8位(即一个字节),中文使用24位(三个字节)来编码。对于英文字符较多的论坛则用UTF-8节省空间。
UTF8是国际编码,它的通用性比较好,外国人也可以浏览论坛 GBK是国家编码,通用性比UTF8差,不过UTF8占用的数据库比GBK大~

35.stringBuffer和StringBuilder组
1.三者在执行速度方面的比较:StringBuilder > StringBuffer > String

36.看servlet和Filter的实现原理
StringBuffer是线程安全的,St不是线程安全的,内部的实现是使用char数

37.什么是rest
一次网站访问的全过程:楼主提到TCP/IP分层的时候用的是网络接口层,那么楼主的TCP/IP分层概念应该是:应用层、传输层、网络层、网络接口层(包含了七层模型中的数据链路层和物理层)。
那么他的主要过程应该是:
一、主机向DNS服务器发起域名解析请求,以得到相对应的IP地址
二、应用层应用HTTP协议发送数据
三、数据到达传输层封装成数据段,主机使用1024以后的随机源端口号,目标端口号为80
四、数据段到达网络层封装成数据包,加入主机源IP地址和目标IP地址
五、数据包到达网络接口层首先封装成数据帧,加入源MAC地址和目标MAC地址(注:此目标MAC地址为本地网关的MAC地址,源和目的MAC地址在数据转发的过程中,会由路由器不断的改变)。封装后将数据转换为物理层的数据流,通过互联网发送至目标服务器。

38.什么时候抛出InvalidMonitorStateException异常?为什么?
调用 wait ()/notify ()/notifyAll ()中的任何一个方法时,如果当前线程没有获得该对象的锁,
那么就会抛出 IllegalMonitorStateException 的异常
也就是说程序在没有执行对象的任何同步块或者同步方法时,
仍然尝试调用 wait ()/notify ()/notifyAll ()时。由于该异常是 RuntimeExcpetion 的子类,
所以该异常不一定要捕获(尽管你可以捕获只要你愿意
作为 RuntimeException,此类异常不会在 wait (),notify (),notifyAll ()的方法签名提及。

39.Collections.synchronizedXX 方法的原理
返回了一个同步容器,在这个同步容器中的所有方法都有一个锁为当前对象或者指定锁的同步块,用这种阻塞同步的方法可以让我们容器同步

40.什么是Future
Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。
1.cancel方法用来取消任务
2.isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。
3.isDone()表示是否完成
4.get()获得执行结果,这个方法会一直阻塞
5.在时间范围内获取执行结果
FutureTask是Future的实现类

41.说出数据连接池的工作机制是什么?
J2EE服务器启动时会建立一定数量的池连接,并一直维持不少于此数目的池连接。
调用:客户端程序需要连接时,池驱动程序会返回一个未使用的池连接并将其表记为 忙。如果当前没有空闲连接,池驱动程序就新建一定数量的连接,新建连接的数量有配置参数决定。
释放:当使用的池连接调用完成后,池驱动程序将此连接表记为空闲, 其他调用就可以使用这个连接。
数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否被 使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超 过最大连接数量时,这些请求将被加入到等待队列中。
数据库连接池的最小连接数和最大连接数的设置要考虑到下列几个因素:

  1. 最小连接数是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费;
  2. 最大连接数是连接池能申请的最大连接数,如果数据库连接请求超过此数,后面的数据库连接请求将被加入到等待队列中,这会影响之后的数据库操作。
  3. 如果最小连接数与最大连接数相差太大,那么最先的连接请求将会获利,之后超过最小连接数量的连接请求等价于建立一个新的数据库连接。不过,这些大于最小连接数的数据库连接在使用完不会马上被释放,它将被放到连接池中等待重复使用或是空闲超时后被释放。

42.存储过程和函数的区别:存储过程是用户定义的一系列sql语句的集合,涉及特定表或其它对象的任务,用户可以调用存储过程,而函数通常是数据库已定义的方法,它接收参数并返回某种类型的值并且不涉及特定用户表。
43.事务是什么?事务是作为一个逻辑单元执行的一系列操作。

44.游标的作用?如何知道游标已经到了最后?游标用于定位结果集的行,通过判断全局变量@@FETCH_STATUS可以判断是否到了最后,通常此变量不等于0表示出错或到了最后。

你可能感兴趣的:(数据库)