接上一篇java并发编程知识总结04,继续总结一下java面试基础知识。
45. 在监视器(Monitor)内部,是如何做线程同步的?程序应该做哪种级别的同 步?
在 java 虚拟机中,监视器和锁在Java虚拟机中是一块使用的。监视器监视一块同步代码块,确保 一次只有一个线程执行同步代码块。每一个监视器都和一个对象引用相关联。线程在获取锁之前不 允许执行同步代码。 一旦方法或者代码块被 synchronized 修饰,那么这个部分就放入了监视器的监视区域,确保一次 只能有一个线程执行该部分的代码,线程在获取锁之前不允许执行该部分的代码 另外 java 还提供了显式监视器( Lock )和隐式监视器( synchronized )两种锁方案
46. 如果你提交任务时,线程池队列已满,这时会发生什么?
有俩种可能:
(1)如果使用的是*队列 LinkedBlockingQueue,也就是*队列的话,没关系,继续添加任务到 阻塞队列中等待执行,因为 LinkedBlockingQueue 可以近乎认为是一个无穷大的队列,可以无限存放 任务
(2)如果使用的是有界队列比如 ArrayBlockingQueue,任务首先会被添加到ArrayBlockingQueue 中,ArrayBlockingQueue 满了,会根据maximumPoolSize 的值增加线程数量,如果增加了线程数量 还是处理不过来,ArrayBlockingQueue 继续满,那么则会使用拒绝策略RejectedExecutionHandler 处理满了的任务,默认是 AbortPolicy
47. 什么叫线程安全?servlet 是线程安全吗?
线程安全是编程中的术语,指某个方法在多线程环境中被调用时,能够正确地处理多个线程之间的 共享变量,使程序功能正确完成。
Servlet 不是线程安全的,servlet 是单实例多线程的,当多个线程同时访问同一个方法,是不能保 证共享变量的线程安全性的。 Struts2 的 action 是多实例多线程的,是线程安全的,每个请求过来都会 new 一个新的 action 分 配给这个请求,请求完成后销毁。 SpringMVC 的 Controller 是线程安全的吗?不是的,和 Servlet 类似的处理流程。 Struts2 好处是不用考虑线程安全问题;Servlet 和 SpringMVC 需要考虑线程安全问题,但是性能 可以提升不用处理太多的 gc,可以使用 ThreadLocal 来处理多线程的问题。
48. 在 Java 程序中怎么保证多线程的运行安全?
方法一:使用安全类,比如 java.util.concurrent 下的类,使用原子类AtomicInteger
方法二:使用自动锁 synchronized。
方法三:使用手动锁 Lock。 手动锁 Java 示例代码如下:
Lock lock = new ReentrantLock();
lock. lock();
try {
System. out. println("获得锁");
} catch (Exception e) {
// TODO: handle exception
} finally {
System. out. println("释放锁");
lock. unlock();
}
49. 你对线程优先级的理解是什么?
每一个线程都是有优先级的,一般来说,高优先级的线程在运行时会具有优先权,但这依赖于线程 调度的实现,这个实现是和操作系统相关的(OS dependent)。我们可以定义线程的优先级,但是 这并不能保证高优先级的线程会在低优先级的线程前执行。
线程优先级是一个 int 变量(从 1-10), 1 代表最低优先级,10 代表最高优先级。 Java 的线程优先级调度会委托给操作系统去处理,所以与具体的操作系统优先级有关,如非特别 需要,一般无需设置线程优先级。 当然,如果你真的想设置优先级可以通过setPriority()方法设置,但是设置了不一定会该变,这个是不准确的
50. 线程类的构造方法、静态块是被哪个线程调用的?
这是一个非常刁钻和狡猾的问题。请记住:线程类的构造方法、静态块是被 new这个线程类所在 的线程所调用的,而 run 方法里面的代码才是被线程自身所调用的。
如果说上面的说法让你感到困惑,那么我举个例子,假设 Thread2 中 new 了Thread1,main 函 数中 new 了 Thread2,那么:
(1)Thread2 的构造方法、静态块是 main 线程调用的,Thread2 的 run()方法是Thread2 自己调用的
(2)Thread1 的构造方法、静态块是 Thread2 调用的,Thread1 的 run()方法是Thread1 自己调用的
51. Java 中怎么获取一份线程 dump 文件?你如何在 Java 中获取线程堆栈?
Dump文件是进程的内存镜像。可以把程序的执行状态通过调试器保存到dump文件中。 在 Linux 下,你可以通过命令 kill -3 PID (Java 进程的进程 ID)来获取 Java应用的 dump 文件。 在 Windows 下,你可以按下 Ctrl + Break 来获取。这样 JVM 就会将线程的 dump 文件打印到标 准输出或错误文件中,它可能打印在控制台或者日志文件中,具体位置依赖应用的配置。
52. 一个线程运行时发生异常会怎样?
如果异常没有被捕获该线程将会停止执行。Thread.UncaughtExceptionHandler是用于处理未捕 获异常造成线程突然中断情况的一个内嵌接口。当一个未捕获异常将造成线程中断的时候,JVM 会使用 Thread.getUncaughtExceptionHandler()来查询线程的 UncaughtExceptionHandler 并将 线程和异常作为参数传递给 handler 的 uncaughtException()方法进行处理。
53. Java 线程数过多会造成什么异常?
线程的生命周期开销非常高 消耗过多的 CPU 资源如果可运行的线程数量多于可用处理器的数量,那么有线程将会被闲置。大量空闲的线程会占 用许多内存,给垃圾回收器带来压力,而且大量的线程在竞争 CPU资源时还将产生其他性能的开 销。 降低稳定性JVM 在可创建线程的数量上存在一个限制,这个限制值将随着平台的不同而不同,并且承受着多个因素 制约,包括 JVM 的启动参数、Thread 构造函数中请求栈的大小,以及底层操作系统对线程的限制 等。如果破坏了这些限制,那么可能抛出OutOfMemoryError 异常。