您的位置:首页 > 科技 > 能源 > Java - 程序员面试笔记记录 实现 - Part3

Java - 程序员面试笔记记录 实现 - Part3

2024/12/23 10:18:16 来源:https://blog.csdn.net/u011010851/article/details/140117268  浏览:    关键词:Java - 程序员面试笔记记录 实现 - Part3

4.1 线程与进程

线程是程序执行的最小单元,一个进程可以拥有多个线程,各个线程之间共享程序的内存空间以及一些进程级资源,但拥有自己的栈空间。

4.3 Java 多线程

方法一:继承 Thread 类,重写 run 方法;

方法二:实现 Runnable 接口,并实现 run 方法;

方法三:实现 Callable 接口,重写 call 方法;

方法四:使用线程池;

4.4 run 和 start 区别

start 方法启动线程后,线程为就绪状态,JVM通过调用线程的 run 方法完成实际的操作。run 方法结束后线程终止。

直接调用 run 方法只会作为普通的函数调用,程序中仍然只有主线程一个线程。

4.5 多线程同步

方法一:Synchronized 关键字,保证同一时间仅有一个线程访问;

方法二:JDK5 新增了 Lock 接口

4.6 Lock

ReentrantLock:重入锁,是指在同一线程中,外部方法获得锁后,内部方法仍然可以回去该锁,若锁不具有可重入性会导致死锁。其持有的是对象监视器。借助 Condition 可以实现等待 / 通知模型。

ReentrantReadWriteLock:将锁分为读锁和写锁,读锁可以在没有写锁的时候被多个线程持有,只有写锁是独占的。如果写锁被一个线程占用,其他线程无论是想要获取读锁还是写锁,都必须等待写锁被释放。

4.7 synchronized 与 lock 的异同

1. synchronized 是托管给 jvm 执行的,lock 的锁定是代码控制的。

2. 资源竞争不激烈的情况下 synchronized 性能更优;资源竞争激烈时 synchronized 性能降低较多。

3. Lock 需要手动控制锁的释放。

4. synchronized 修饰方法时,静态 static 方法持有的是类锁,非静态方法持有的是对象锁。

4.8 sleep 和 wait 的区别

1. sleep 是用来控制自身流程的,wait 用于线程间的通讯。

2. sleep 不释放锁;wait 释放锁;

4.8 补充 - yield

Thread.yield() 方法可以让当前线程放弃当前的CPU时间片,但这并不意味着当前线程会立即停止执行。实际上,yield 方法只是提示线程调度器(Thread Scheduler),当前线程愿意让出对CPU的使用,但是否真的会立即让出CPU时间片,取决于线程调度器的实现和当前的线程调度策略。

4.9 终止线程

stop():释放线程已经锁定的资源,可能会导致程序执行的不确定性。

suspend():由于不会释放锁容易发生死锁。

一般建议让线程自行结束。或者设置一个标记位结束(线程处于非运行状态可以触发异常来安全结束线程)

4.10 死锁

必要条件

1. 互斥:资源具有排他性。

2. 请求和保持:线程至少已经持有一个资源并申请新的资源。

3.不剥夺:已获得的资源未释放时不可被剥夺。

4.环路等待。

4.11 守护线程 Daemon

JVM 中只有守护线程在运行时,JVM会自动关闭。

4.12 Join

线程合并:调用该方法的线程执行完 run() 后再执行 join 后的代码。

4.13 线程抛出的异常

线程抛出的异常无法使用 try/catch 捕捉。JDK 5 提供了Thread.UncaughtExceptionHandler 来处理线程中未被捕获的异常。

4.14 线程池

ThreadPoolExecutor 是 ExecutorService 的一个实现。可以最大化利用线程空闲时间和空间。

处理任务的流程:

1. 线程池的线程数量小于 corePoolSize ,创建新线程执行任务。

2. 线程池的数量大于 corePoolSize,暂时把任务存到工作队列等待。

3. 工作队列也满了,线程数小于最大限制,创建新线程执行,若已经超过最大限制,执行拒绝策略。

newFixedThreadPool: 线程池大小固定。

newCachedThreadPool:线程池基本大小为 0,空闲线程会在60s内销毁。每个新任务都会有线程执行。适用于执行速度较快且较小的场景。线程池的大小完全依赖 JVM 能创建的最大线程大小。

newSingleThreadExecutor:单线程的线程池。

newScheduledThreadPool:可以按一定的周期执行任务。

4.15 ThreadLocal

threadLocal.get 获取到的值对每个线程是唯一的。

线程被创建时,线程的对象存储在堆中,栈中存放引用;ThreadLocal 对象被初始化时,存储在堆中的,同时栈中保存引用。当 ThreadLocal 的方法被调用时, JVM会根据引用找到实例,查看 ThreadLocalMap 实例是否被创建并初始化使用。即 ThreadLocal 会把指定值和当前线程绑定在一个 map 里。

4.16 Latch

指定线程等待计数线程完成工作后再执行 latch.await() 之后的代码。CountDownLatch 不可以重用。

4.17 Barier

等待一组线程完成某个条件后再一起执行后续功能的能力。

4.18 Fork / Join

将大任务分割成小的任务后并运行,最后将小任务的最终结果合并为大任务。需保持子任务独立。内部实际为线程池。

4.19 CAS

CAS 保证操作是原子性的,sun.misc.Unsafe 提供一系列相关方法。

ABA问题:更新时增加一个版本号。

4.20 线程调度与优先级

线程的五个状态

1. 新建:创建后的线程进入这个状态。

2. Runnable:start 方法调用后进入可运行状态

3. Running:获得 CPU使用权

4. Blocking:阻塞,放弃CPU;同步阻塞(获取锁失败)会放入锁池。等待阻塞(wait)放入等待队列中。其他(IO、sleep、join)

5. Dead:结束

Java 中优先级可以划分为10个等级。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com