1、volatile 关键字的作用
1、 对于可见性,Java 提供了 volatile 关键字来保证可见性和禁止指令重排。 volatile 提供 happens-before 的保证,确保一个线程的修改能对其他线程是可见的。当一个共享变量被 volatile修饰时,它会保证修改的值会立即被更新到主内存中,当有其他线程需要读取时,它会去内存中读取新值。
2、 从实践角度而言,volatile 的一个重要作用就是和 CAS 结合,保证了原子性,详细的可以参见 java.util.concurrent.atomic 包下的类,比如 AtomicInteger。
3、 volatile 常用于多线程环境下的单次操作(单次读或者单次写)。
2、Java 中用到的线程调度算法是什么?
计算机通常只有一个 CPU,在任意时刻只能执行一条机器指令,每个线程只有获得CPU 的使用权才能执行指令。所谓多线程的并发运行,其实是指从宏观上看,各个线程轮流获得 CPU 的使用权,分别执行各自的任务。在运行池中,会有多个处于就绪状态的线程在等待 CPU,JAVA 虚拟机的一项任务就是负责线程的调度,线程调度是指按照特定机制为多个线程分配 CPU 的使用权。(Java是由JVM中的线程计数器来实现线程调度)
有两种调度模型:
分时调度模型和抢占式调度模型。
1、 分时调度模型是指让所有的线程轮流获得 cpu 的使用权,并且平均分配每个线程占用的 CPU 的时间片这个也比较好理解。
2、 Java虚拟机采用抢占式调度模型,是指优先让可运行池中优先级高的线程占用CPU,如果可运行池中的线程优先级相同,那么就随机选择一个线程,使其占用CPU。处于运行状态的线程会一直运行,直至它不得不放弃 CPU。
3、简单描述一下(分代)垃圾回收的过程
分代回收器有两个分区:老生代和新生代,新生代默认的空间占比总空间的 1/3
,老生代的默认占比是 2/3
。
新生代使用的是复制算法,新生代里有 3 个分区:Eden
、To Survivor
、From Survivor
,它们的默认占比是 8:1:1
,它的执行流程如下:
当年轻代中的Eden区分配满的时候,就会触发年轻代的GC(Minor GC)。具体过程如下:
1、 在Eden区执行了 第一次
GC之后,存活的对象会被移动到其中一个Survivor分区(以下简称from)
2、 Eden区再次GC,这时会采用复制算法,将Eden和from区一起清理。存活的对象会被复制到to区。接下来,只需要清空from区就可以了
4、什么是可重入锁(ReentrantLock)?
举例来说明锁的可重入性
public class UnReentrant{
Lock lock = new Lock();
public void outer(){
lock.lock();
inner();
lock.unlock();
}
public void inner(){
lock.lock();
//do something
lock.unlock();
}
}
outer中调用了inner,outer先锁住了lock,这样inner就不能再获取lock。其实调用outer的线程已经获取了lock锁,但是不能在inner中重复利用已经获取的锁资源,这种锁即称之为 不可重入可重入就意味着:线程可以进入任何一个它已经拥有的锁所同步着的代码块。
synchronized、ReentrantLock都是可重入的锁,可重入锁相对来说简化了并发编程的开发。
5、线程池有什么优点?
1、 降低资源消耗:重用存在的线程,减少对象创建销毁的开销。
2、 提高响应速度。可有效的控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
3、 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
4、 附加功能:提供定时执行、定期执行、单线程、并发数控制等功能。
6、你有哪些手段来排查 OOM 的问题?
1、 增加两个参数 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof,当 OOM 发生时自动 dump 堆内存信息到指定目录
2、 同时 jstat 查看监控 JVM 的内存和 GC 情况,先观察问题大概出在什么区域
3、 使用 MAT 工具载入到 dump 文件,分析大对象的占用情况,比如 HashMap 做缓存未清理,时间长了就会内存溢出,可以把改为弱引用
7、什么是线程异步?什么是线程同步?
1、 线程同步:同时只有一条线程执行一个任务
2、 线程异步:同时有多条线程可以执行执行任务
8、Java 中,受检查异常 和 不受检查异常的区别?
受检查异常编译器在编译期间检查。对于这种异常,方法强制处理或者通过 throws 子句声明。其中一种情况是 Exception 的子类但不是 RuntimeException 的子类。非受检查是 RuntimeException 的子类,在编译阶段不受编译器的检查。
9、OOP 中的 组合、聚合和关联有什么区别?
如果两个对象彼此有关系,就说他们是彼此相关联的。组合和聚合是面向对象中的两种形式的关联。组合是一种比聚合更强力的关联。组合中,一个对象是另一个的拥有者,而聚合则是指一个对象使用另一个对象。如果对象 A 是由对象 B 组合的,则 A 不存在的话,B一定不存在,但是如果 A 对象聚合了一个对象 B,则即使 A 不存在了,B 也可以单独存在。
10、Java网络编程有几种?
TCP编程
UDP编程