JUC复习及面试题学习
资源来自沉默王二、小林coding、竹子爱熊猫、代码随想录
一、JUC
1、进程与线程
进程是对运行程序的封装,是系统进行资源调度和分配的最小单位。
线程是进程的子任务,是CPU调度分配的基本单位
不同的进程之间很难数据共享,同进程下的不同线程之间可以共享数据
2、创建线程的三种方式
1、继承Thread类,重写run方法
public class mythread extends Thread {@Override public void run() {System.out.println("myThread");} }// mythread t1=new mythread; t1.setName("名字"); t1.start();
2、实现Runnable接口,重写run方法
public myrunable implements Runnable {@Override public void run () { System.out.println("myrunable"); }} //my runable aa=new myrunable(); //Thread t1=new Thread(aa,"名字"); //t1.start();
3、实现Callable接口
public class mycall implements Callable<String> { public String call()throws Exception {return "mycall start";} }public static void main (String []args) {FutureTask<String> task=new FutureTask<String>(new CallerTask());//启动线程new Thread(task).start();try {//等待执行完成,并获取返回结果String result=task.get();System.out.println(result);} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}}
run与start的区别:
run是封装线程执行的代码,start是启动线程,然后让jvm调用此线程的run方法。
sleep():暂停x毫秒,需要捕获异常
join():等该线程执行完,才轮到其他线程执行,需要捕获异常
setDaemon(true);设置该线程为守护线程
3、Java内存模型
JMM 是抽象的,他是用来描述一组规则,通过这个规则来控制各个变量的访问方式,围绕原子性、有序性、可见性等展开。运行时内存区域是物理实现,由JVM具体管理内存的分配和回收
编译器优化指令重排
处理器指令重排
三大特性:原子性、可见性、有序性
两大内存:主内存、工作内存
先行发生原则happens-before:
4、volatile关键字
禁止指令重排,解决内存不可见性问题。通过插入内存屏障来实现。
能保证可见性和做到禁止指令重排做到有序性,但是它不能保证原子性
就是线程在写操作完成前别的线程还可能读到旧值。
5、synchronized关键字
是一种悲观锁
为当前对象加锁,为class对象加锁、为指定对象加锁
synchronized同步方法:保证任意时刻只有一个线程能操作该方法。但一个对象只有一把锁,当一个线程获取了该对象的锁之后,其他线程无法获取该对象的锁,所以无法访问该对象的其他被
synchronized
修饰的对象实例方法。如果是不同对象则是可以的,但这样无法保证线程安全如果锁的是static方法,则锁的是class对象,其他对象也都无法访问。
synchronized同步代码块:可对(class、this、某个对象)上锁
synchronized 就是可重入锁,一个线程得到一个对象锁后,再次请求该对象锁,这是是允许的
四种锁机制:
- 无锁状态
- 偏向锁状态
- 轻量级锁状态
- 重量级锁状态
偏向锁:偏向锁在资源无竞争情况下消除了同步语句
实现原理:一个线程在第一次进入同步块时,会在对象头和栈帧中的锁记录里存储锁偏向的线程 ID。当下次该线程进入这个同步块时,会去检查锁的 Mark Word 里面是不是放的自己的线程 ID。若之前线程不在则更新为当前线程ID,否则升级该锁为轻量级锁
把偏向锁这个默认功能给关闭:
-XX:UseBiasedLocking=false
轻量级锁:
一个线程获得锁的时候发现是轻量级锁,会把锁的 Mark Word 复制到自己的栈帧里面。然后线程尝试用 CAS 将锁的 Mark Word 替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失败,表示 Mark Word 已经被替换成了其他线程的锁记录,说明在与其它线程竞争锁,当前线程就尝试使用自旋来获取锁。
如果自旋到一定程度未获取锁,则会升级成重量级锁。
在释放锁时,当前线程会使用 CAS 操作将 Displaced Mark Word 的内容复制回锁的 Mark Word 里面
重量级锁:
依赖于操作系统的互斥锁。对于重量级锁,如果线程尝试获取锁失败,它会直接进入阻塞状态,等待操作系统的调度。
6、CAS
CAS是乐观锁的实现方式,是无锁的原子操作。一旦多个线程发生冲突,乐观锁通常使用一种称为 CAS 的技术来保证线程执行的安全性。
CAS机制的最终实现是依赖于CPU原子性指令实现,CAS是一种操作系统原语范畴的指令,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断
CAS是通过C++实现的,它包含三个操作数:要更新的变量(V)、预期值(E)和新值(N),流程是先读取变量的值与预期值一样,则赋新值,否则不进行操作循环再次读取判断,直到成功为止。
CAS的问题:
1、ABA 问题,就是一个值原来是 A,变成了 B,又变回了 A。这个时候使用 CAS 是检查不出变化的,但实际上却被更新了两次。
ABA 问题的解决思路是在变量前面追加上版本号或者时间戳。
2、CAS 多与自旋结合。如果自旋 CAS 长时间不成功,会占用大量的 CPU 资源。
解决思路是让 JVM 支持处理器提供的pause 指令。
3、对于多个共享变量,CAS 就无法保证操作的原子性,这时通常有两种做法:
使用锁,使用AtomicReference类
7、AQS(抽象队列同步器)
8、ThreadLocal
ThreadLocal是线程本地变量,执行时为变量在每一条线程中创建一个副本,这个副本只有每条线程自己可以访问。
二、面试题
1、多线程安全的理解?
线程安全问题产生的根本原因:多条线程同时对一个共享资源进行非原子性操作时会诱发线程安全问题
为了避免线程安全我们可以从它的三要素来考虑:
首先是原子性,就是说一个操作要么完全执行要么完全失败,不会出现中间状态。可以通过原子操作或synchronized关键字来实现
其次是可见性,指的是当一个线程修改了共享变量,其他线程能立即看到。可以用volatile来保证可见性。
最后是有序(活跃)性,保证线程不会因死锁、活锁等问题而无法执行。
2、并发和并行
并发是指单核cpu上,多个任务交替执行,通过时间片轮转的方式实现,是逻辑上的同时运行。
而并行式多核cpu上,多个任务在同一刻同时运行,是真正在物理上做到了同时运行
3、 进程和线程和协程
进程是操作系统分配资源的最小单位,比如我们启动一个应用就是开启了一个进程。
线程是进程中的独立执行单元。多个线程可以共享同一个进程的资源,如内存;每个线程都有自己独立的栈和寄存器。线程是操作系统调度的最小单位
协程被视为比线程更轻量级的并发单元,由用户态程序自身调度
4、线程间如何通信的?
由于Java 采用的是共享内存的并发模型 ,所以线程ab之间要进行通信,a先将共享变量的副本刷新到主内存中,然后b再从主内存中读取共享变量,这样就完成了通信
5、线程的六种状态(生命周期)
new:线程创建但未启动,已经分配了资源
runnable: 线程已启动,可能正在运行也可能等待获取CPU的时间片
blocked:线程获取锁失败被阻塞
waiting:无休止等待,需要其他线程显示唤醒
TIMED_waiting:有期限等待,然后自动返回可运行状态
terminated:终止 ,生命周期结束,不再被重新启动,可调用Interrupt方法强制终止
6、创建线程的方式
1、写一个类,该类继承Thread(extends),然后重写父类的run方法,main里生成该类的一个对象再调用start方法即可。
2、写一个类实现Runnable接口(implements),然后重写该接口的run方法,main里生成该类的一个对象,将该对象作为参数传入Thread类生成Thread类对象,调用Thread对象的start方法即可
3、写一个类实现Callable接口(注意是泛型)并重写call方法,main里生成该类的一个对象,再将该对象通过参数生成一个FutureTask<>对象,(泛型里类型一样),然后将FutureTask对象通过参数生成Thread对象,再调用start方法。
7、start和run方法的区别
调用
start()
会创建一个新的线程,并异步执行run()
方法中的代码。直接调用
run()
方法只是一个普通的同步方法调用,所有代码都在当前线程中执行,不会创建新线程。没有新的线程创建,也就达不到多线程并发的目的。如果需要实现多线程执行,则应该调用 start 方法来启动新线程。
8、sleep和wait的区别
1、sleep属于Thread类的静态方法,而wait是Object类的实例方法
2、sleep期间其它线程无法获取锁,而wait会释放锁
3、sleep无需事先获取锁,而wait必须先获取锁
4、sleep会进入timewaiting,结束后线程自动进入就绪状态,wait会进入waiting需要其它线程调用notify等方法来唤醒它
9、如何保证线程安全
线程安全是指在并发环境下,多个线程访问共享资源时,程序能够正确地执行,而不会出现数据不一致的问题。
为了保证线程安全,可以使用 synchronized 关键字对方法加锁,对代码块加锁。线程在执行同步方法、同步代码块时,会获取类锁或者对象锁,其他线程就会阻塞并等待锁。
如果需要更细粒度的锁,可以使用 ReentrantLock 并发重入锁等。
如果需要保证变量的内存可见性,可以使用 volatile 关键字。
对于简单的原子变量操作,还可以使用 Atomic 原子类。
对于线程独立的数据,可以使用 ThreadLocal 来为每个线程提供专属的变量副本。
对于需要并发容器的地方,可以使用 ConcurrentHashMap、CopyOnWriteArrayList 等。
10、守护线程了解吗?与用户线程有什么区别?
Java 中的线程分为两类,一种是守护线程,另外一种是用户线程。
比如main方法所在的线程就是一个用户线程,而垃圾回收线程就是一个守护线程。
如果所有的用户线程都结束了,那么JVM会退出,而守护线程可能继续在运行,但并不影响JVM的退出。
11、简单说说线程间的通信方式
多个线程可以通过 volatile 和 synchronized 关键字访问和修改同一个对象,从而实现线程间通信
关键字 volatile 可以用来修饰成员变量,对变量的修改会同步刷新回共享内存,保证所有线程对变量访问的可见性。
关键字 synchronized 可以修饰方法,或者同步代码块,确保多个线程在同一个时刻只有一个线程在执行方法或代码块。
还可以使用wait和notify,线程调用wait方法会释放锁并等待(一般配合synchronized来上锁)
而notify会唤醒一个在当前对象上等待的线程
12、讲一个线程安全的使用场景
单例模式下,多个线程同时尝试创建实例,但单例类必须保证只创建一个实例
饿汉式通过类加载时初始化单例对象来确保线程安全
懒汉式在第一次使用时才初始化对象,使用双重检查锁来确保线程安全,volatile来确保可见性,synchronized来确保同步
13、ThreadLocal是什么?
ThreadLocal是一种线程局部变量的工具类,允许每个线程拥有自己独立的副本
Thread类中,有个ThreadLocalMap 的成员变量。 ThreadLocalMap内部维护了Entry数组,每个Entry代表一个完整的对象,key是ThreadLocal本身,value是ThreadLocal的泛型对象值。
使用的时候先定义一个ThreadLocal变量,然后线程去调用变量的set\get等方法就可以使用了
14、ThreadLocal有哪些优点
1、每个线程访问的变量副本都是独立的,避免了共享变量引起的线程安全问题(而且不能继承)
2、在同一个线程内使用ThreadLocal可以减少参数的传递,降低代码之间的耦合度,使代码更加清晰和模块化。
3、由于ThreadLocal避免了线程间的同步开销,所以在大量线程并发执行时,相比传统的锁机制,它可以提供更好的性能
15、说说ThreadLocal的原理
当我们创建一个 ThreadLocal 对象并调用 set 方法时,其实是在当前线程中初始化了一个 ThreadLocalMap
ThreadLocalMap 是 ThreadLocal 的一个静态内部类,它内部维护了一个 Entry 数组,key 是 ThreadLocal 对象(是弱引用),value 是线程的局部变量,这样就相当于为每个线程维护了一个变量副本
16、什么是弱引用、强引用?
强引用是如果一个对象具有强引用,即使系统内存不足,垃圾回收器也不会回收这个对象,只有在不再有任何强引用指向这个对象时,才会被回收。
弱引用是垃圾回收时只要发现弱引用对象就回收,而引用处置为Null
ThreadLocal里Entry对象的key存的就是ThreadLocal变量的弱引用
17、ThreadLocal内存泄漏是怎么回事?
由于ThreadLocal里的Entry对象,key是弱引用,value是强引用,当ThreadLocal变量被回收时,key变为null,该Entry已经无用了,而value是强引用无法回收。
解决方案是使用完ThreadLocal后调用remove方法,回收所有key为null的Entry对象。
(这里设计弱引用就是方便在内存不足时能回收变为弱引用对象的ThreadLocal)
18、ThreadLocalMap底层说说,为什么冲突采用线性探测法?
ThreadLocalMap 虽然被叫做 Map,但它并没有实现 Map 接口,是一个简单的线性探测哈希表。
底层的数据结构也是数组,数组中的每个元素是一个 Entry 对象,Entry 对象继承了 WeakReference,key 是 ThreadLocal 对象,value 是线程的局部变量。
比如它的set()
方法,通过 key 的哈希码与数组长度取模,计算出 key 在数组中的位置由于ThreadLocalMap 设计的目的是存储线程私有数据,不会有大量的 Key,所以采用线性探测更节省空间。
拉链法还需要单独维护一个链表,甚至红黑树,不适合 ThreadLocal 这种场景。
19、ThreadLocalMap扩容机制了解吗?
ThreadLocalMap 并不会直接在元素数量达到阈值时立即扩容,而是先清理被 GC 回收的 key,然后扩容。
初始容量为16,负载因子为三分之二
ThreadLocalMap 采用的是“先清理再扩容”的策略,扩容时,数组长度翻倍,并重新计算索引,如果发生哈希冲突,采用线性探测法来解决。
20、说一下Java内存模型
Java 内存模型是一个抽象模型,用来描述多线程环境中共享变量的内存可见性。
共享变量存储在
主内存
中,每个线程都有一个私有的本地内存
,存储了共享变量的副本。
- 当一个线程更改了本地内存中共享变量的副本,它需要 刷新到主内存中
- 当一个线程需要读取共享变量时,它一版会从本地内存中读取。
21、 了解volatile吗
volatile主要有两个作用,保证变量的可见性,和防止指令重排
进行写操作时,会在变量写入后加入写屏障指令,强制将内存中变量值刷新回主内存中,并让其他线程的该变量失效
底层汇编通常使用lock 指令来实现
进行读操作时,会插入读屏障指令,强制让本地内存中变量失效从主内存再读取并更新。
22、volatile和synchronized的区别
volatile 关键字用于修饰变量,确保该变量的更新操作对所有线程是可见的,即一旦某个线程修改了 volatile 变量,其他线程会立即看到最新的值。但它只能保证单个读写操作的原子性
synchronized 关键字用于修饰方法或代码块,确保同一时刻只有一个线程能够执行该方法或代码块,从而实现互斥访问。可以保证代码块的原子性
23、说说synchronized关键字
synchronized修饰普通方法时上锁的是该对象,修饰静态方法时上锁的时类的Class对象,修饰代码块时给括号里的对象上锁(this,Class,其它对象)
synchronized 加锁代码块时,JVM 会通过
monitorenter
、monitorexit
两个指令来实现同步synchronized 依赖对象头的 Mark Word 进行状态管理,支持无锁、偏向锁、轻量级锁,以及重量级锁。
24、synchronized怎么保证可见性、有序性?
可见:加锁时必须从主内存读,释放锁时必须刷回主内存
有序:通过monitorenter和monitorexit来保证代码块内指令不会重排
25、synchronized如何实现可重入性
synchronized 之所以支持可重入,是因为 Java 的对象头包含了一个 Mark Word,用于存储对象的状态,包括锁信息。 若线程内多次获取同一个锁则计数器加1.只有所有锁都被释放该线程才彻底释放锁。
26、synhronized锁升级了解吗?
锁升级其实是通过改变对象头里的MarkWord标志位来实现的,一共有四种锁状态
无锁:就是没有锁,MarkWord存储hashcode和其它信息
偏向锁:当线程第一次获取锁时,会进入偏向模式。Mark Word 会记录线程 ID。下次进入 synchronized 时,如果还是同一个线程,可以直接执行,无需额外加锁。
轻量级锁:当多个线程在不同时段获取同一把锁,JVM 会采用轻量级锁来避免线程阻塞。此时偏向锁会被撤销,对象的锁状态会由偏向锁升级为轻量级锁。而所有线程通过CAS自旋去抢锁
重量级锁:如果自旋超过一定的次数或者线程竞争太多时,轻量级锁就会升级为重量级锁。在这种情况下,JVM 会在操作系统层面创建一个互斥锁,所有线程排队执行
27、synchronized和reentrantlock的区别了解吗?
二者都是可重入锁
Synchronized是由JVM内部的monitor机制实现的,可以自动加锁和解锁
而reentrantlock是基于AQS实现的,需要手动加锁和解锁。如果再高并发场景下倾向于使用reentrantlock,因为它支持Condition能提供更细粒度的锁控制,并且同时支持公平锁和非公平锁,应对场景更多。并且无需像synchronized那样上下文切换来运行,更快一些
28、Lock接口了解吗?
Lock是JUC里的接口,支持超时等待、公平与非公平锁、以及支持Condition能提供更细粒度的锁控制。最常用的实现类包括reentrantlock.
这个接口的lock()方法是核心方法之一,reentrantlock实现的步骤是尝试通过 CAS 来获取锁。如果当前锁没有被持有,会将锁状态设置为 1,表示锁已被占用。否则,会将当前线程加入到 AQS 的等待队列中。
29、说说AQS
AQS 是一个抽象类,它维护了一个共享变量 state 和一个线程等待队列。如果被请求的共享资源处于空闲状态,则当前线程成功获取锁;否则,将当前线程加入到等待队列中,当其他线程释放锁时,通知等待线程去竞争锁
其中state用volatile修饰,保证可见性
同步队列是用Node类实现,是一个先进先出的双向链表
而且它支持两种模式:
独占模式:如reentrantlock,只能有一个线程获取锁
共享模式:如Semaphore\CountDownLatch,多个线程可以同时获取锁
30、说说ReentrantLock实现原理
ReentrantLock 是基于 AQS 实现的 可重入排他锁,使用 CAS 尝试获取锁,失败的话会进入 CLH 阻塞队列,支持公平锁、非公平锁,可以中断、超时等待。
通过计数器state来跟踪锁的状态,如果线程尝试获取锁时state=0,则会直接加锁,state置1,如果多次获取该锁,则state不断++。后来的线程发现state不为0则会加入等待队列中。
这里有非公平锁和公平锁两种情况,默认是非公平锁:
非公平锁发现state不为0,则会立即CAS抢一下锁,进入队列前再抢一次没抢到则进入队列
公平锁则是所有发现state不为0的线程都直接进入等待队列,按等待时间来唤醒(参数+true就创建了)
31、CAS了解吗?
CAS 是一种乐观锁,用于比较一个变量的当前值是否等于预期值,如果相等,则更新值,否则重试。它的实现需要三个参数,变量、预期值、新值。
先从内存中读取当前值与预期值比较,如果相等则修改,不等则返回新值放弃更新。
它具有原子性,这是由于底层汇编用CMPXCHG实现的,所以有原子性
32、CAS有什么问题?
它主要有三个问题:
1、ABA问题:如果变量由A改成了B再改成了A则会认为没有发生变化。
解决方案是使用版本号和时间戳
2、自旋开销大:CAS 失败时会不断自旋重试,如果一直不成功,会给 CPU 带来非常大的执行开销。
解决方案是加上一个次数的限制,超过了则挂起线程
3、只能保证一个变量的原子操作,涉及到多个变量就不行了
解决方案是将变量包装成一个对象使用 AtomicReference 进行 CAS 更新。
33、Java有哪些保证原子性的方法
1、使用原子类atomicInteger等,底层实现是CAS+volatile
2、使用JUC里的reentrantLock锁等
3、使用sychronized关键字
34、了解死锁吗?
死锁发生在多个线程相互等待对方释放锁时
生成的原因是资源一次只能被一个线程占用,其它线程只能等待不能抢夺,并且形成了环形等待链
解决死锁可以规定获取锁的顺序,只能按一种顺序取锁。或者发现无法获取某资源时先释放已有资源再获取
死锁问题排查可以使用jps查看当前进程,使用jstack查看堆栈信息。
35、 聊聊线程同步和互斥
同步意味着线程要按照一定顺序执行,互斥意味线程只见要抢占资源。
具体实现的话互斥可以使用synchronized关键字和lock接口的实现类来完成
同步可以使用countDownLatch来完成
36、聊聊悲观锁乐观锁
悲观锁认为每次访问共享资源时都会发生冲突,所在在操作前一定要先加锁(synchronized、reentrantLock等)
乐观锁认为冲突不会总是发生,所以在操作前不加锁,而是在更新数据时检查是否有其他线程修改了数据。如果发现数据被修改了就会重试。常常采用不断的CAS去修改,比如原子类就是这么做的
37、 CountDownLatch了解吗?
CountDownLatch 是 JUC 中的一个同步工具类,用于协调多个线程确保主线程在多个子线程完成任务后继续执行。
它的核心思想是通过一个倒计时计数器来控制多个线程的执行顺序。
在使用时先初始化一个 CountDownLatch 对象,指定一个计数器的初始值,表示需要等待的线程数量。
然后在每个子线程执行完任务后,调用
countDown()
方法,计数器减 1。接着主线程调用
await()
方法进入阻塞状态,直到计数器为 0主线程才会继续执行。
38、说一下ConcurrentHashMap的实现
ConcurrentHashMap
是 Java 并发包中提供的线程安全哈希表实现,它通过 分段锁(Java 7) 和 CAS + synchronized(Java 8) 实现高效并发访问.jdk7中整个 Map 会被分为若干段,每个段都可以独立加锁,每个段维护一个HashEntry为元素的单向链表,其中put流程是先定位到具体的段,再通过 ReentrantLock 进行加锁操作
jdk8中的 ConcurrentHashMap 取消了分段锁,采用 CAS + synchronized 来实现更细粒度的桶锁,并且使用红黑树来优化链表以提高哈希冲突时的查询效率,性能比 JDK 7 有了很大的提升。put流程为计算哈希找到位置进行CAS插入(桶为空才行),如果失败或有节点则用Synchronized来操作。冲突链表超过8则转为红黑树。
get方法的话由于value是volatile的所以直接读就可以了
(补充,因为1.8桶锁粒度小,冲突的频率地低了所以使用synchronized不用reentrantlock,低竞争下synchronized接近无锁会性能更快)
39、说一下CopyOnWriteArrayList的原理
CopyOnWriteArrayList 是 ArrayList 的线程安全版本,适用于读多写少的场景。它的核心思想是写时复制技术 写操作时创建一个新数组,修改后再替换原数组,这样就能够确保读操作无锁,从而提高并发性能
数组使用volatile保证可见性,使得可以并发读
写操作通过reentrantlock上锁来保证线程安全
但是在复制的时候一个新数组,可能会开销很大
40、什么是线程池?
线程池是用来管理线程的工具,它可以减少线程的创建和销毁开销
JAva中使用ThreadPoolExecutor来使用线程池。
工作流程为:创建线程池,提交任务,如果核心线程满了放入等待队列,等待队列满了启用新线程直至达到最大线程数。启用的非核心线程不会立即销毁,而是会等待直到超时才销毁。关闭线程池用shutdown
41、线程池的主要参数?
corePoolSize:核心线程数,长期存活,执行任务的主力。
maximumPoolSize:线程池允许的最大线程数。
workQueue:任务队列,存储等待执行的任务。
handler:拒绝策略,任务超载时的处理方式。也就是线程数达到 maximumPoolSiz,任务队列也满了的时候,就会触发拒绝策略。
threadFactory:线程工厂,用于创建线程,可自定义线程名。
keepAliveTime:非核心线程的存活时间,空闲时间超过该值就销毁。
unit:keepAliveTime 参数的时间单位:
42、线程池的拒绝策略?
- AbortPolicy:默认的拒绝策略,会抛异常。
- CallerRunsPolicy:让提交任务的线程自己来执行这个任务,也就是调用 execute 方法的线程。
- DiscardOldestPolicy:等待队列会丢弃队列中最老的一个任务,也就是队列中等待最久的任务,然后尝试重新提交被拒绝的任务。
- DiscardPolicy:丢弃被拒绝的任务,不做任何处理也不抛出异常。
43、线程池参数设置有经验吗?
核心线程数(corePoolSize)设置的经验:
CPU密集型:corePoolSize = CPU核数 + 1尽量减少上下文切换,优化CPU使用率
IO密集型:corePoolSize = CPU核数 x 2 由于线程长时间等待,可以设置更多的线程来提高并发
44、有几种常见的线程池?
固定大小的线程池
Executors.newFixedThreadPool(int nThreads);
,适合用于任务数量确定,且对线程数有明确要求的场景。例如,IO 密集型任务、数据库连接池等。缓存线程池
Executors.newCachedThreadPool();
,适用于短时间内任务量波动较大的场景。例如,短时间内有大量的文件处理任务或网络请求。定时任务线程池
Executors.newScheduledThreadPool(int corePoolSize);
,适用于需要定时执行任务的场景。例如,定时发送邮件、定时备份数据等。单线程线程池
Executors.newSingleThreadExecutor();
,适用于需要按顺序执行任务的场景。例如,日志记录、文件处理等。
45、线程池的几种状态说说?
RUNNING 状态的线程池可以接收新任务,并处理阻塞队列中的任务;
SHUTDOWN 状态的线程池不会接收新任务,但会处理阻塞队列中的任务;
STOP 状态的线程池不会接收新任务,也不会处理阻塞队列中的任务,并且会尝试中断正在执行的任务;
TIDYING 状态表示所有任务已经终止;
TERMINATED 状态表示线程池完全关闭,所有线程销毁。
46、Fork/Join了解吗?
Fork/Join 框架是 Java 7 引入的一个并行框架,主要用于分治算法的并行执行。这个框架通过将大的任务递归地分解成小任务,然后并行执行,最后再合并结果,以达到最高效率处理大量数据的目的。
Fork/Join 的线程池(fork/joinpool)采用 工作窃取算法,空闲线程会主动从其他线程的任务队列偷任务执行,提高 CPU 利用率。
相关文章:
JUC复习及面试题学习
资源来自沉默王二、小林coding、竹子爱熊猫、代码随想录 一、JUC 1、进程与线程 进程是对运行程序的封装,是系统进行资源调度和分配的最小单位。 线程是进程的子任务,是CPU调度分配的基本单位 不同的进程之间很难数据共享,同进程下的不同线…...
The_Planets_Earth靶场笔记(VulnHub)
环境说明: kali地址:192.168.144.128 靶机地址:192.168.144.181 靶机网卡改为NAT模式。 靶机下载地址: https://download.vulnhub.com/theplanets/Earth.ova 一.信息收集: 1.主机探测: 使用如下命令…...
dawgctf 2025 writeup
dawgctf 2025 writeup 赛事信息pwnJust Parry Lol miscDont Touch My FoneThe BirdsMystery Signal IinternsProjectSuspicious scriptSpectral SecretsCaddyshack forensicsKeeping on ScheduleJust Packets CryptoCipher For Good osintEs ist alles in ButterLook Long and …...
机器学习(神经网络基础篇)——个人理解篇6(概念+代码)———参数优化篇
1 在声明一个类中,构建一个属于类的函数,前面为什要加上“self”? 就像下面这一串代码: class TwoLayerNet:def __init__(self, input_size, hidden_size, output_size,weight_init_std0.01):# 初始化权重self.params {}self.p…...
AI速读:解锁LLM下Game Agent的奇妙世界
在 AI 浪潮中,大语言模型(LLMs)正重塑游戏智能体格局。想知道基于 LLMs 的游戏智能体如何运作,在各类游戏中有何惊艳表现,未来又将走向何方? 大型语言模型(LLMs)的兴起为游戏智能体的…...
个人所得税
文章目录 一、名词解释二、个人所得税计算方法 (举例)1.累计预扣预缴应纳税所得额、本期应预扣预缴税额2.个人所得税预扣率表一3.个人所得税计算举例 三、专项附加扣除政策介绍四、年度汇算清缴政策介绍五、常见问答 一、名词解释 累计预扣法是指扣缴义务人在一个纳税年度内预…...
DEA-Net:基于细节增强卷积和内容引导注意力的单图像去雾
IEEE TIP 2024 | DEA-Net:基于细节增强卷积和内容引导注意力的单图像去雾 DEA-Net: Single image dehazing based on detail-enhanced convolution and content-guided attention paper name: DEA-Net: Single image dehazing based on detail-enhanced convolutio…...
StringEscapeUtils:给你的字符串穿上“防弹衣“——转义工具类深度解析
各位代码勇士们好!今天我们要聊的是Apache Commons Lang3中的StringEscapeUtils工具类。如果说StringUtils是瑞士军刀,那StringEscapeUtils就是你的字符串保镖,专门负责在各种危险场合保护你的字符串安全! 一、为什么需要字符串转…...
Sharding-JDBC 系列专题 - 第二篇:广播表(Broadcast Tables)
Sharding-JDBC 系列专题 - 第二篇:广播表(Broadcast Tables) 本系列专题旨在帮助开发者深入掌握 Sharding-JDBC,一个轻量级的分布式数据库中间件。本篇作为系列的第二篇文章,将详细讲解 广播表(Broadcast Tables) 的概念、配置、使用场景、工作原理以及实战案例。广播表…...
PySide6 GUI 学习笔记——常用类及控件使用方法(常用类矩阵QRect)
文章目录 一、构造与初始化方法二、坐标与尺寸获取三、坐标与尺寸设置四、几何运算方法五、移动与调整方法六、状态判断方法七、类型转换方法八、操作符重载九、静态方法十、特殊方法附录方法速查表注意的问题交集和并集图解 📘 PySide6.QtCore.QRect 使用整数精度定…...
常见的页面报错
目录 1、 405报错,方法不允许 2、 404报错,未找到资源 404报错的两种可能: 1、前端找不到后端的资源: 2、后端找不到返回的资源: 3、 400报错,错误的请求 后端返回的数据类型与前端不匹配 前端传递的参…...
人机共跑,马拉松人型机器人同跑
马拉松比赛对人形机器人来说,是一场对硬件极限的测试,涉及机械、传感器、能源管理等多个方面。用户问的是硬件方面的考察和改进,这意味着我的回答需要聚焦于硬件性能,而不是算法或软件的优化。 对人形机器人硬件的考研 机械结构与…...
ES6 第一讲 变量定义 堆与栈 字符串的扩展和数值型的扩展
文章目录 1.ES6变量定义2.ES6堆和栈3.字符串的扩展3.1 模板字符串3.2 判断是否以指定的字符串开头或结尾3.3 字符串重复输出3.4 填充方法3.5 去除前后字符串空格3.6 返回参数指定位置的字符 4. 数值型的扩展4.1 二进制0B 八进制0O4.2 判断是否是一个无穷大的数字 (判…...
Linux 动、静态库的实现
前言:当我们写了一段代码实现了一个方法,如果我们不想把方法的实现过程暴露给别人看,可以把代码打包成一个库,其中形成后缀为.a的是静态库,后缀为.so的为动态库;当别人想使用你的方法时,把打包好…...
linux多线(进)程编程——(9)信号量(二)
前言 上一篇文章我们讲解了信号量的基础用法,这一篇文章我们承接上面的内容,给大家进一步提升对信号量的理解。如果没有看过上一篇文章,请大家移步linux多线(进)程编程——(9)信号量(一) 案例…...
编码器---正交编码器
一、正交编码器定义与核心作用 正交编码器(Orthogonal Encoder),又称增量式编码器,是一种通过输出两路相位差90的脉冲信号(A相、B相)来测量旋转角度、速度和方向的传感器。其核心优势是通过A/B相的脉冲顺序…...
【HDFS入门】HDFS故障排查与案例分析:从日志分析到实战解决
目录 1 HDFS故障排查概述 2 三大常见故障类型解析 2.1 块丢失问题处理流程 2.2 副本不足问题架构 2.3 DataNode无法启动诊断 3 日志分析实战技巧 3.1 NameNode日志分析框架 3.2 DataNode日志分析流程 4.1 实战案例分析 4.2 集群性能突然下降 4.2 数据读写异常处理 …...
爆肝整理!Stable Diffusion的完全使用手册(二)
继续介绍Stable Diffusion的文生图界面功能。 往期文章详见: 爆肝整理!Stable Diffusion的完全使用手册(一) 下面接着对SD的文生图界面的进行详细的介绍。本期介绍文生图界面的截图2,主要包含生成模块下的采用方法、调度类型、迭…...
经典算法 表达式求值
表达式求值 问题描述 给你一个只包含、-、*、/、0、1、2、3、4、5、6、7、8、9的字符串求出该字符串所代表的表达式的值。这里的除法,为了简便,为整数除法,所以答案一定也是一个整数。保证0不作被除数。 示例输入 (16*(141))((13)*(74))*…...
【Java】接口interface学习
参考资料::黑马程序员入门到飞起上 1 概述 在学习完抽象类后,我们了解到抽象类中既可以包含抽象方法,也能有普通方法、构造方法以及成员变量等。而接口则是一种更为彻底的抽象形式。在JDK7及之前的版本中,接口内全部为抽象方法&…...
数据结构实验7.1:二叉树的遍历
文章目录 一,实验目的二,实验描述三,基本要求四,算法分析五,实验操作六,示例代码七,运行效果一,实验目的 深入理解树与二叉树的基本概念,包括节点、度、层次、深度等,清晰区分二叉树与一般树的结构特点,为后续学习和应用打下坚实基础。熟练掌握用递归方法实现二叉树…...
seata db模式,nacos注册中心,spring boot ,spring cloud ,jdk1.8 完成的配置步骤
1. 环境准备 确保以下环境已经安装并正常运行: JDK 1.8MySQL(或其他支持的数据库)Nacos Server(用于注册中心和配置中心)Seata Server 2. 配置 Seata Server (1) 下载并解压 Seata 从 Seata 官方 GitHub 下载最新版…...
C++进阶-多态
文章目录 C进阶--多态概念多态的定义及实现多态的构成条件实现多态的两个重要条件虚函数虚函数的重写及覆盖协变析构函数的重写(面试被问及最好需要举例说明)override和final关键字重载,重写(覆盖),隐藏&am…...
Linux教程-常用命令系列三
文章目录 1. 网络安全常用命令1. su (Switch User)2. chmod (Change Mode)3. chown (Change Owner)4. ps (Process Status)5. who6. top7. free8. kill9. gedit10. find总结 2. 字符串显示命令2.1 基本语法2.2 常用选项2.3 核心功能与示例2.3.1 输出字符串2.3.2 输出变量2.3.3 …...
GIS开发笔记(9)结合osg及osgEarth实现三维球经纬网格绘制及显隐
一、实现效果 二、实现原理 按照5的间隔分别创建经纬线的节点,挂在到组合节点,组合节点挂接到根节点。可以根据需要设置间隔度数和线宽、线的颜色。 三、参考代码 //创建经纬线的节点 osg::Node *GlobeWidget::createGraticuleGeometry(float interv…...
nuxt3前端开发以及nuxt3和nuxt2项目的详细差异点
以下是 Nuxt 3 前端开发的详细指南以及与 Nuxt 2 的核心差异总结,涵盖配置、开发模式、API 变化等关键方面: 一、Nuxt 3 前端开发核心要点 1. 项目初始化 # Nuxt 3 npx nuxi init <project-name> cd <project-name> npm install npm run dev# Nuxt 2 (对比) np…...
Android学习总结之APK打包流程
一、预处理阶段(编译前准备) 1. AIDL 文件处理(进程间通信基础) 流程: 用于实现 Android 系统中不同进程间的通信(IPC)。在项目构建时,AIDL 编译器会将 .aidl 文件编译为 Java 接口…...
java面试篇(常见的集合底层原理)
集合 1、arraylist源码分析 三种构造方法: 扩容的逻辑: 2、ArrayList的底层实现原理是什么? ArrayList listnew ArrayList(10)中的list扩容几次 3、如何实现数组和List之间的转换 4、LinkedList和arraylist的区别 5、hashmap的实现原理 二叉…...
RAG框架精选2
原文链接:https://i68.ltd/notes/posts/20250406-llm-rag2/ 清华Hyper-RAG 使用超图驱动的RAG对抗LLM幻觉论文链接:https://arxiv.org/pdf/2504.08758项目仓库:https://github.com/iMoonLab/Hyper-RAG清华Hyper-RAG:利用超图建模高阶关系,让DeepSeek/Q…...
Redis进阶学习
什么是Redis? Redis是一个key-value结构的非关系型数据库,将数据存储在内存中,结构简单(五种数据结构:string、list、set、zset、hash),数据读写速度快,还可以将数据持久化到硬盘上。…...
【读书笔记·VLSI电路设计方法解密】问题63:为什么可测试性设计对产品的财务成功至关重要
可测试性设计至关重要,因为我们不希望将劣质或故障部件交付给客户。向客户交付过多不良部件意味着财务灾难,更会损害企业声誉并导致商业机会流失。 若设计中未嵌入可测试性设计(DFT),区分良品与不良品的唯一方法就是由应用工程师或客户在实际应用环境中测试芯片。此时芯片…...
Federated Weakly Supervised Video Anomaly Detection with Multimodal Prompt
标题:联邦弱监督视频异常检测的多模态提示方法 原文链接:https://ojs.aaai.org/index.php/AAAI/article/view/35398 源码链接:https://github.com/wbfwonderful/Fed-WSVAD 发表:AAAI-2025 摘要(Abstract) …...
计算机视觉与深度学习 | LSTM原理,公式,代码,应用
LSTM(长短期记忆网络)详解 一、原理 LSTM(Long Short-Term Memory)是RNN的改进版本,通过引入门控机制(输入门、遗忘门、输出门)和细胞状态(Cell State),有效解决传统RNN的梯度消失/爆炸问题,擅长捕捉长距离依赖关系。 核心思想: 细胞状态(C_t):贯穿整个时间步…...
UI界面工程,如何使用控制台
我们通常会使用print函数向控制台输出调试信息。但创建UI界面工程时,默认不会显示控制台。 通过如下方法切换到控制台 项目属性—链接器—系统—子系统—窗口改为控制台...
mysql——基础知识
关键字大小写不敏感 查看表结构中的 desc describe 描述 降序中的 desc descend 1. 数据库的操作 1. 创建数据库 create database 数据库名;为防止创建的数据库重复 CREATE DATABASE IF NOT EXISTS 数据库名;手动设置数据库采用的字符集 character set 字符集名;chars…...
UE虚幻4虚幻5动画蓝图调试,触发FellOutOfWorld事件和打印输出,继续DeepSeek输出
找到了一个pdf,本来想写个翻译的,但还是算了,大概看了下,这类文档很全面,内容很多,但都不是我要的,我想要一个动画蓝图,搜索Montage,或者Anim 只占了一行(几百…...
52单片机LED实验
文章目录 前言点亮一个LEDLED闪烁 LED灯亮灭交替LED流水灯 前言 我所用的板子是普中的STC89C52RC,创建文件的过程中如果你发现keil文件找不到单片机依赖,那怎么办呢 下面从创建新项目讲起 首先打开keil软件,点击project new一个新的projec…...
【C++详解】C++入门(一)命名空间、缺省参数、函数重载
文章目录 一、命名空间命名空间的基本特性命名空间的使用 二、C输入输出用法三、缺省参数(默认参数)定义用法 四、函数重载 一、命名空间 命名空间的基本特性 #include <stdio.h> #include <stdlib.h>int rand 10;int main() {// 编译报错:error C23…...
AWS Linux快速指南:5分钟搭建多用户图形界面
一、概述 本指南将帮助您在AWS上快速部署一个支持多用户、带图形界面和浏览器的Linux环境。我们将使用Ubuntu Server作为基础,配合轻量级的Xfce桌面环境和VNC服务。同时,我们还将提供不同用户规模下的实例规格推荐。 二、实例规格推荐 根据您的用户规模,我们推荐以下EC2实例…...
kotlin,编码、解码
kotlin写程序确实简洁,就是函数式编程对我这种用惯了过程的,换思想有难度。package org.exampleimport java.io.File import java.io.FileNotFoundExceptionval byteToHanzi mapOf(0x00 to "凡", 0x01 to "周", 0x02 to "张&q…...
从零创建 Docker 镜像(基于 OCI 格式)
更现代的 OCI 镜像格式,采用了 OCI Image Format Specification,其中文件引用使用 blobs/sha256/<hash> 的形式,层和配置存储在 blobs/sha256/ 目录下,并且包含 LayerSources 字段。这种格式在较新的 Docker 版本和 OCI 兼容…...
JavaScript 版本号比较
问题描述: 实现 : <script>const compare function(v1,v2){const arr1 v1.split(.)const arr2 v2.split(.)for(let i 0;i<arr1.length||i<arr2.length;i){const a arr1[i]||0const b arr2[i]||0if(a>b){return 1}else if(a<b){…...
MySQL为什么默认使用RR隔离级别?
大家好,我是锋哥。今天分享关于【MySQL为什么默认使用RR隔离级别?】面试题。希望对大家有帮助; MySQL为什么默认使用RR隔离级别? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 MySQL 默认使用 RR(Repeatable Read)…...
第37讲|AI+农业气象建模:预测极端天气对农业的影响
目录 ✨ 导语:天气不可控,但影响可以预测 📦 一、数据准备:融合农业与气象 ⚡ 二、极端天气如何“定义”? 🔧 三、模型选择与结构设计 🔁 时间序列模型:LSTM 🎯 非时序模型:XGBoost / LightGBM 🧪 四、案例实战:用LSTM预测小麦产量下降风险(受极端天气…...
(done) 吴恩达版提示词工程 1. 引言 (Base LLM 和 Instruction Tuned LLM)
url: https://www.bilibili.com/video/BV1Z14y1Z7LJ/?spm_id_from333.337.search-card.all.click&vd_source7a1a0bc74158c6993c7355c5490fc600 LLM 有两种: 1.基础 LLM,通过文本训练数据预测后面的内容。 这种 LLM 当你给它提问:What is…...
Vue如何实现样式隔离
1. 使用 CSS Modules CSS Modules 允许你在 Vue 组件中定义局部作用域的 CSS,这样可以避免全局样式的冲突 步骤如下: 在你的 Vue 组件中,创建一个 <style> 标签并添加 module 属性。 <template><div :class"$style.c…...
Sentinel源码—6.熔断降级和数据统计的实现二
大纲 1.DegradeSlot实现熔断降级的原理与源码 2.Sentinel数据指标统计的滑动窗口算法 2.Sentinel数据指标统计的滑动窗口算法 (1)滑动窗口介绍 (2)StatisticSlot使用滑动窗口算法进行数据统计 (1)滑动窗口介绍 一.滑动窗口原理 滑动窗口不会指定固定的时间窗口起点与终点…...
B+树删除和测试
B树删除和测试 5.1 高级接口:B 树作为键值存储 在本章中,我们将实现 B 树的高级接口,使其能够作为键值存储(Key-Value Store)使用。这些接口包括插入和删除操作,并处理根节点的维护。 1. 插入接口 1.1 I…...
常用算法解析:从基础排序到图论应用
一、算法基础与设计原则 算法是计算机解决问题的核心工具,其五大基本特性决定了程序的可靠性: 有穷性:算法必须能在有限步骤内终止确定性:每步操作无歧义可行性:可被计算机执行输入输出:具备数据交互能力…...
Java Web项目(一)
框架 java web项目总工分为两部分:客户端(前端)和服务端(后端) 客户端发起请求,服务端接受请求并进行处理 发起请求的方式:from表单、jQuery ajax from表单 造成全局的变化,在发…...