多线程
1. 线程的状态
| 状态名称 | 描述 | 触发条件 |
|---|---|---|
| NEW(新建) | 线程对象被创建但未调用start()方法 | Thread thread = new MyThread(); |
| RUNNABLE(可运行) | 线程已启动,等待 CPU 调度执行run()方法 | 调用start()方法后 |
| BLOCKED(阻塞) | 线程因等待锁资源而暂停执行 | 进入同步代码块/方法时锁被其他线程持有 |
| WAITING(等待) | 线程主动放弃 CPU,进入无限等待状态 | 调用wait()、join()或LockSupport.park() |
| TIMED_WAITING(超时等待) | 线程在指定时间内等待(如睡眠或限时等待) | 调用sleep(long)、wait(long)或join(long) |
| TERMINATED(终止) | 线程执行完毕或异常退出 | run()方法正常结束或抛出未捕获异常 |
2. 线程池大小如何设定 *
生产环境中, java线程池的大小的设定与硬件资源和并发需求密切相关。通常可以考虑CPU核心数, 内存容量, 网络带宽等硬件资源, 并结合预估的并发请求量来确定线程池大小, 以充分利用资源并保持合理的并发处理能力。
3. 线程池的拒绝策略有哪些
4. 线程池是一个服务一个还是整体使用一个, 为什么
每个微服务用一个线程池, 避免不同业务模块的线程池彼此之间相互影响。不至于出现某个服务的线程池出现问题导致其他服务的线程池不可用
5. synchronized和lock的区别
synchronized和lock的区别是: synchronized是java关键字, 是内置的同步机制, 能修饰方法或代码块, 锁的获取是隐式的, 底层实现原理是基于JVM内置监视器锁; 而lock是一个接口, 提供更灵活的同步机制, 可以手动控制锁的获取和释放, 底层实现可以是ReentrantLock等, 性能在高竞争环境下通常较好
6. 什么情况下会产生死锁, 如何解决
产生死锁的情况是在多线程程序中, 每个线程都持有一些资源, 并且等待其他线程释放它所需的资源。解决死锁可采取以下方法: 避免死锁的发生, 通过破坏死锁生的四个必要条件之一来预防; 检测死锁, 使用算法检测出是否发生死锁, 并采取相应的措施解除死锁; 恢复死锁, 即进行资源的强制抢占或进行回滚操作, 将进程回退到安全状态以解除死锁
7. ThreadLocal是一个什么样的技术
ThreadLocal是一种java技术,他运行在多线程环境中维护线程私有的变量副本。底层自己实现了一个ThreadLocalMap的map集合来存储每个线程的变量副本。ThreadLocal使用弱引用作为键来维护各个线程的变量副本,但变量本身由线程强引用。在使用ThreadLocal时,可能会出现内存泄漏的问题。如果线程结束了,但ThreadLocal中的变量没有被手动清理,那么该变量会一直存在于ThreadLocalMap中,导致内存泄漏。可以用过手动调用remove()方法将变量从ThreadLocal中移除。
锁
1.说说你对JUC的了解
JUC是java.util.concurrent的缩写, 该包参考自EDU.oswego.cs.dl.util.concurrent, 是JSR 166标准规范的一个实现。JSR 166是一个关于java并发编程的规范提案, 在JDK中该规范由java.util.concurrent包实现。即JUC是java提供的并发包,其中包含了一些并发编程用到的基础组件。
2. 说说你对AQS的理解
抽象队列同步器AbstractQueuedSynchronizer,是用来构建锁或者其他同步组件的骨架类,减少了各功能组件实现的代码量,也解决了在实现同步器涉及的大量细节问题,例如等待线程采用FIFO队列操作的顺序。在不同的同步器中还可以定义一些灵活的标准来判断某个线程是应该通过还是等待。
AQS采用模板方法模式,在内部维护了n多的模板的方法的基础上,子类只需要实现特定的几个方法就可以实现自己的需求。
3.volatile的用法及原理
volatile是一个java关键字,用来保证可见性和有序性, 当多个线程操作共享变量时,会存在数据不一致的问题。因为在java内存模型中,有工作内存和主内存,每个线程都有自己的工作内存,里边存储变量的副本,当对一个普通变量进行写操作时,不会立即同步到主内存,因此其他线程不能立即看到最新的值,这就是内存可见性问题。通过volatile关键字修饰的变量可以解决这个问题,JVM底层是通过内存屏障来实现,当对一个变量进行读取时,插入读屏障,表示先从主内存读取,当对一个变量进行写入后,插入写屏障,表示立即同步到主内存,这样就解决了可见性问题,保证了数据一致性。
编译器有时为了指令更符合CPU流水线特性对指令重新排序,但在多线程环境下可能导致致命问题。通过volatile关键字可以防止指令重排。
但volatile不能解决原子性问题,因为每个线程都有工作内存,各自线程计算完后同步到主内存会存在覆盖的问题,所以对于如a++这样的复合操作就可能导致线程安全问题。
4.悲观锁和乐观锁的区别
悲观锁和乐观锁其实是个概念并非是具体的锁,悲观锁悲观地认为在并发的情况下,线程获取资源会有线程安全问题,所以在一开始获取线程资源是加锁,保证线程安全,适合写频繁的场景。乐观锁乐观地认为并发冲突不会发生,只在进行更新数据的时候去判断之前是否有线程更新了这个数据。
5.说说对于CAS的理解
CAS(Compare and Swap)是乐观锁的一个经典实现,用于保证多线程环境下的数据的一致性,CAS通过比较内存中的值和预期中的值是否相等来决定是否能成功访问共享资源。适用于读大于写的场景,相比于直接加锁,它的性能更高。CAS会出现ABA问题,即当线程读取变量值为A,其他线程将值从A改为B,再改回A,原线程执行CAS时发现值仍是A,误以为未被修改过,可以通过添加版本号来解决。

10万+

被折叠的 条评论
为什么被折叠?



