news 2026/4/18 5:30:06

源码-JDK

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
源码-JDK

面试题

并发编程三大特性?

原子性:多个操作执行期间不会发生上下文切换。
可见性:线程操作JVM主内存数据时会先从主内存中拿取,在工作内存中计算完之后,再同步会主内存,同步到主内存之前的结果其他线程不可见。可以通过volatile实现。
有序性:CPU在执行java指令时,底层会进行优化导致指令重排序。可以通过volatile实现。

锁分类

悲观锁与乐观锁:获取悲观锁后其他线程会挂起。乐观锁不涉及线程挂起,例如CAS(存在ABA、自旋次数过多两个问题)。
可重入锁与不可重入锁:当期线程获取锁之后,是否还可以继续获取该锁。
公平锁与非公平锁:先排队的线程先获取锁
互斥锁与共享锁:是否允许多个线程同时持有。

synchronized优化

JDK1.6版本中,synchronized就做了大量的优化,和ReentrantLock性能差不多了。
①锁消除:不需要加锁操作的可以直接将锁操作去掉。
②锁粗化:锁范围扩大。在循环内部加的锁资源,这样会导致至少要执行100万次的加锁和释放锁的操作,太过频繁。锁膨胀的优化,会将synchronized锁的范围,膨胀到for循环之外,这样一来,加锁一次,完成100万次循环的业务操作,然后释放锁一次即可,大大滴提升了性能。
③锁升级:JDK1.5时,获取锁失败就直接挂起了,导致线程阻塞。锁升级解决尽量降低出现线程阻塞的情况。偏向锁 => 轻量级锁 => 重量级锁。
偏向锁:如果一个锁基本上只有一个线程抢占持有,那这个线程下一次获取锁时直接获取即可,不需要进行CAS判断。
轻量级锁:获取锁失败后会先进行CAS尝试,直到达到自旋阈值。
重量级锁:传统的synchronized方式,如果拿锁成功,走人,拿锁失败,线程挂起。

ReentrantLock和synchronized的区别

synchronized拿不到锁只能死等。ReentrantLock提供了多种方式获取锁资源。
synchronized只支持非公平锁。ReentrantLock支持公平锁和非公平锁,默认是非公平锁。
synchronized底层是基于对象实现的。ReentrantLock是基于AQS(抽象类)实现的。

加载properties文件

publicclassTest{publicstaticvoidmain(String[]args)throwsIOException{Propertiesproperties=newProperties();// resources目录下InputStreamis=Test.class.getClassLoader().getResourceAsStream("abc.properties");try{properties.load(is);System.out.println(properties.get("key1"));ResourceBundlebundle=ResourceBundle.getBundle("abc");System.out.println(bundle.getString("key1"));}catch(IOExceptione){e.printStackTrace();}finally{is.close();}}}

WebService

跨编程语言、跨操作系统的远程调用技术,可用于发布服务端接口,供不同的客户端调用。
Java中有三种WebService规范,主要使用的是JAX-WS

ReentrantLock.Condition

用于实现等待通知机制。
集合容量是3,集合已满时生产者等待,集合已空时消费者等待。

publicclass等待通知机制{staticReentrantLocklock=newReentrantLock();staticConditioncondition=lock.newCondition();staticLinkedList<Integer>list=newLinkedList<>();staticAtomicBooleanab=newAtomicBoolean(true);publicstaticvoidmain(String[]args){newThread(()->{for(inti=0;i<100;i++){lock.lock();try{while(list.size()==3){condition.await();}list.addLast(i);System.out.println("生产者生产 =>"+i);condition.signalAll();if(i==99){ab.set(false);}}catch(InterruptedExceptione){e.printStackTrace();}finally{lock.unlock();}}}).start();newThread(()->{while(ab.get()){lock.lock();try{while(list.size()==0){condition.await();}System.out.println("消费者消费 =>"+list.removeFirst());condition.signalAll();}catch(InterruptedExceptione){e.printStackTrace();}finally{lock.unlock();}}}).start();}}

一、ReentrantLock

AbstractQueuedSynchronizer(AQS)

抽象队列同步器,属性:
state:锁的状态。在ReentrantLock中,state=0代表当前锁未被持有,state=1当前当前锁被某个线程持有,state>1代表当前锁不仅被某个线程持有,而且被重入。
exclusiveOwnerThread:保存持有当前锁的线程。
head、tail:等待队列中的头节点跟尾节点。
Node节点属性有:
thread:当前等待节点的线程实例
prev:上一个节点。
next:下一个节点。
waitStatus:当前等待节点的状态。如果waitStatus < 0,代表当前节点的线程释放锁后,立马唤醒头节点的下一个节点。

lock()

publicfinalvoidacquire(intarg){if(!tryAcquire(arg)&&acquireQueued(addWaiter(Node.EXCLUSIVE),arg))selfInterrupt();}

lock()中公平锁与非公平锁的区别:
公平锁直接调用acquire();,而非公平锁直接尝试CAS将state从0替换成1,如果成功设置exclusiveOwnerThread=当前线程,逻辑结束,如果失败acquire();
1、tryAcquire() 尝试获取锁
①如果state=0,尝试CAS将state从0替换为1,如果替换成功将exclusiveOwnerThread赋为当前线程,当前线程成功获取到锁,逻辑结束。
②判断持有锁的线程是否是当前线程,如果是当前线程,state++,锁重入成功,逻辑结束。
tryAcquire()中公平锁与非公平锁的区别:
非公平锁在state=0时直接尝试CAS将state从0替换成1,而公平锁会判断有没有前驱结点(head.next.thread!=当前线程),如果没有前驱结点,才会尝试CAS将state从0替换成1。
2、addWaiter() 加入等待队列
①根据当前线程创建Node节点。
②如果tail=null,说明等待队列为空,CAS将head从null替换成new Node(),如果替换成功,tail=head
③如果tail不为null,循环CAS将tail替换为node,替换成功后,原tail.next=node,node.pre=原tail
PS:如果第二步成功,还是会走第三步。

3与4在acquireQueued()中:

finalbooleanacquireQueued(finalNodenode,intarg){booleanfailed=true;try{booleaninterrupted=false;for(;;){finalNodep=node.predecessor();if(p==head&&tryAcquire(arg)){setHead(node);p.next=null;// help GCfailed=false;returninterrupted;}if(shouldParkAfterFailedAcquire(p,node)&&parkAndCheckInterrupt())interrupted=true;}}finally{if(failed)cancelAcquire(node);}}

acquireQueued()逻辑大概是:在循环里,先走第四步if prev == head && tryAcquire(),如果成功逻辑结束,如果失败走第三步shouldParkAfterFailedAcquire()线程阻塞,如果被唤醒继续走循环里的逻辑。
3、shouldParkAfterFailedAcquire() 线程阻塞
①如果上一个节点的waitStatus>0,往上遍历,将上一个节点移除node.prev = node.prev.prev,直到上一个节点的waitStatus不大于0
②如果上一个节点的waitStatus!=-1,通过CAS循环将上一个节点的waitStatus替换成-1
③如果上一个节点的waitStatus=-1了,通过LockSupport.park()阻塞当前节点的线程
4、if prev == head && tryAcquire() 被唤醒后尝试获取锁
①当前线程被唤醒后,如果上一个节点是头节点,再次通过第一步tryAcquire()去尝试获取锁,获取锁成功后让头节点head=node;
②如果上一个节点不是head或者tryAcquire()获取锁失败后,再次通过第三步shouldParkAfterFailedAcquire()线程阻塞,直到再次被唤醒。

tryLock()

逻辑与lock()的第一步tryAcquire()一致(不管公平锁或者非公平锁走的都是非公平锁的tryAcquire())。

tryLock(long timeout, TimeUnit unit)

tryAcquireNanos()

publicfinalbooleantryAcquireNanos(intarg,longnanosTimeout){if(Thread.interrupted())thrownewInterruptedException();returntryAcquire(arg)||doAcquireNanos(arg,nanosTimeout);}

doAcquireNanos()

privatebooleandoAcquireNanos(intarg,longnanosTimeout){finallongdeadline=System.nanoTime()+nanosTimeout;finalNodenode=addWaiter(Node.EXCLUSIVE);booleanfailed=true;try{for(;;){finalNodep=node.predecessor();if(p==head&&tryAcquire(arg)){setHead(node);p.next=null;// help GCfailed=false;returntrue;}nanosTimeout=deadline-System.nanoTime();if(nanosTimeout<=0L)returnfalse;if(shouldParkAfterFailedAcquire(p,node)&&nanosTimeout>spinForTimeoutThreshold)LockSupport.parkNanos(this,nanosTimeout);if(Thread.interrupted())thrownewInterruptedException();}}finally{if(failed)cancelAcquire(node);// 有一步是将waitStatus改成1}}

与lock()步骤类似,区别在于:
第三步shouldParkAfterFailedAcquire() 线程阻塞会有阻塞时间,到达阻塞时间后自动唤醒,不会一直阻塞。
第四步if prev == head && tryAcquire() 被唤醒后尝试获取锁如果获取锁失败会先判断是否超时,如果超时直接获取锁失败,如果没超时才会走第三步线程阻塞。

unlock()

release()

publicfinalbooleanrelease(intarg){if(tryRelease(arg)){Nodeh=head;if(h!=null&&h.waitStatus!=0)unparkSuccessor(h);returntrue;}returnfalse;}

1、tryRelease()
①判断持有锁的线程是否是当前线程,如果不是,抛出异常。
②state–,如果state减完之后不等于0,逻辑结束。如果state减完之后等于0,设置持有锁的线程等于null,走第二步。
2、unparkSuccessor()
①如果头节点的waitStatus不等于0,找出头节点下的第一个waitStatus≤0的节点,通过LockSupport.unpark()唤醒节点。

二、ThreadPoolExecutor

七大参数+2

maximumPoolSize
keepAliveTime
corePoolSize
BlockingQueue
TimeUnit
ThreadFactory
RejectHandler
1、AtomicInteger ctl
前三位代表线程池状态runState,后29为当前线程池的线程个数workCount
线程池状态从小到大依次为running-1、shutdown0、stop1、tidying2、terminated3
running:接受新任务并且可以执行队列中的任务。
shutdown:不接收新任务但是可以执行队列中的任务。
stop(shutdownNow()):不接收新任务并且不执行队列中的任务。
tidying:线程池状态变为shutdown、stop后,当所有任务已终止,工作线程数为0,线程池状态会自动更新为tidying状态,并执行terminated()方法。
terminated:执行完terminated()方法之后,线程池状态会自动更新为terminated状态。
2.workers:工作线程集合。

参数配置

最大线程数配置:
计算型任务:CPU核心数 + 1
IO型任务:CPU核心数 * 2
计算公式:线程数 = CPU核心数 * (1 + 线程等待时间 / 线程运行总时间)
CPU核心数获取方法:Runtime.getRuntime().availableProcessors();
核心线程数配置:
如果是长期并发量都特别高的业务,可以将核心线程数与最大线程数都设置为计算出来的线程数。
如果是偶尔并发量特别高的业务,可以将核心线程数设置的小一点,最大线程数设置为计算出来的线程数。
任务队列大小配置:
根据自己能接受的最长等待时间决定,假如核心线程数是100,每个任务耗时1s,则任务队列中的第1000个任务可能需要等待10s才能执行到。

execute()

publicvoidexecute(Runnablecommand){if(command==null)thrownewNullPointerException();intc=ctl.get();if(workerCountOf(c)<corePoolSize){if(addWorker(command,true))return;c=ctl.get();}if(isRunning(c)&&workQueue.offer(command)){intrecheck=ctl.get();if(!isRunning(recheck)&&remove(command))reject(command);elseif(workerCountOf(recheck)==0)addWorker(null,false);}elseif(!addWorker(command,false))reject(command);}

1、if (workCount < corePoolSize) addWorker()

如果工作线程数小于核心线程数,通过addWorker(runnable,true)创建核心工作线程

2、if (runState == running) workQueue.offer(runnable)

①如果不满足第一点,即工作线程数大于等于核心线程数时,
②判断当前线程池状态是否是running,如果是则将任务添加到任务队列,
③如果添加成功,判断工作线程数是否等于0,如果等于0,需要通过addWorker(null,false)创建一个工作线程用于处理任务。

3、if (workCount >= corePoolSize && workQueue is full) addWorker(runnable,false)

如果工作线程数大于等于核心线程数并且工作队列是满的,则通过addWorker(runnable,false)创建非核心线程。
如果创建非核心线程失败,说明当前的工作线程数已经达到了最大线程数,走拒绝策略。

addWorker(runnable,boolean)

用于创建工作线程。
如果runnable != null,此时创建的工作线程用于执行execute()中传递来的任务并且执行工作队列中的任务。
如果runnable == null,此时创建的工作线程仅仅用于执行工作队列中的任务。

1、if (runState == running || (runState == shutdown && runnable==null && workQueue isNotEmpty)) continue;

①如果线程池状态是运行中,则可以正常创建工作线程。
②如果线程池的状态不是运行中,但是是shutdown,此时虽然不能接收新任务,但是可以工作队列中的任务,再判断runnable是否为null,并且工作队列是否不为空,如果都满足,说明要创建的工作线程仅仅用于执行工作队列中的任务。
③除了以上两种情况,直接return false;

2、判断当前工作线程数是否超过核心线程数或者最大线程数(方法参数决定)

3、new Worker() workers.add(worker) workCount++ thread.start()

①创建工作线程,其中工作线程封装了线程工厂创建的线程。
②将工作线程放到workers集合中
③工作线程数+1
④调用worker对象中的线程对象的start()方法开启线程,thread的run()方法中会调用worker对象的runWorker()方法。

runWorker(worker)

1、while(firstTask != null || getTask() != null)

①firstTask是创建工作线程时指定的任务,会首先执行。
②firstTask执行完之后,不断从任务队列中取任务
③如果任务为null,finally里调用processWorkerExit()方法,该工作线程结束

2、runnable.run()

①执行任务。
②如果任务抛异常了,会走到finally中,finally里调用processWorkerExit()方法,该工作线程结束。

3、processWorkerExit() TODO:JRB

①workCount–
②workers.remove(worker)

getTask()

get runnable from workQueue

判断该工作线程是不是非核心线程(workCount > corePoolSize),
①如果是非核心线程,通过Runnable r = workQueue.poll(keepAliveTime)阻塞获取队列中的任务,其中等待时间是非核心线程的最大空闲时间。
②如果是核心线程,通过Runnable r = workQueue.take()一直阻塞的拉取任务。
③如果拉取到任务(r!=null),直接返回该任务。
④如果没有拉取到任务(r==null),说明在非核心线程的最大空闲时间内没有拉取到任务。此时判断当前线程是否是非核心线程(workCount > corePoolSize),如果还是,return null

三、JUC

1、atomic包

AtomicBoolean

AtomicInteger

value用volatile修饰。底层调用unsafe类的方法,CAS循环。

LongAddr

AtomicReference

AtomicMarkableReference

保证reference与boolean的原子性。简单解决ABA问题。

Stuzs=newStu("zs",18);AtomicMarkableReference<Stu>amr=newAtomicMarkableReference<>(zs,true);boolean[]markHolder=newboolean[1];Stustu=amr.get(markHolder);StuexpectedReference=stu;StunewReference=newStu("ls",29);booleanexpectedMark=markHolder[0];booleannewMark=!expectedMark;booleanresult=amr.compareAndSet(expectedReference,newReference,expectedMark,newMark);

AtomicStampedReference

保证reference与int的原子性。解决ABA问题。

Stuzs=newStu("zs",18);AtomicStampedReference<Stu>amr=newAtomicStampedReference<>(zs,1);int[]stampHolder=newint[1];Stustu=amr.get(stampHolder);StuexpectedReference=stu;StunewReference=newStu("ls",29);intexpectedStamp=stampHolder[0];intnewStamp=expectedStamp+1;booleanresult=amr.compareAndSet(expectedReference,newReference,expectedStamp,newStamp);

2、locks包

ReentrantLock(AQS、LockSupport)

ReentrantReadWriteLock

3、直接JUC下

ThreadPoolExecutor

CompletableFuture

// 创建方式CompletableFuture<Void>c1=CompletableFuture.runAsync(()->System.out.println("123"),threadPool);CompletableFuture<Integer>c2=CompletableFuture.supplyAsync(()->1,threadPool);

作用一:多个任务同时操作,都会有返回结果,让这些任务先执行,主线程等待,等所有任务执行完之后,对每个任务的执行结果进行处理。
CompletableFuture.supplyAsync()封装到list
CompletableFuture.allOf(list).join()
CompletableFuture.get()获取结果
作用二:任务串行执行
执行完A任务后,返回结果作为参数,调用handle()执行B任务。
作用三:任务的交互
thenCombine() 两个任务的结果作为参数,创建新的任务去执行。

CountDownLatch

await()阻塞当前线程,直到执行了指定次数的countDown()

Exchanger

两个线程直接交换数据。

CyclicBarrier

创建CyclicBarrier时可以传递runnable,在等待被唤醒后先执行该runnable后线程再往下执行。
await()方法会阻塞,直到到达执行数量的await()方法都被执行才会唤醒。

CopyOnWriteArrayList

ConcurrentHashMap

ArrayBlockingQueue

LinkedBlockingQueue

================================================

API使用

ScheduledExecutorService

publicstaticvoidmain(String[]args)throwsInterruptedException{ScheduledExecutorServicescheduler=Executors.newScheduledThreadPool(2);System.out.println("~~~~~"+newDate());// 延迟2s后执行一次性任务scheduler.schedule(()->{System.out.println("~~~~~~~~~");},2,TimeUnit.SECONDS);// 延迟5s开始执行任务,第一个任务开始时,间隔2s开始执行第二个任务,可能存在两个任务同时执行scheduler.scheduleAtFixedRate(()->{try{TimeUnit.SECONDS.sleep(3);}catch(InterruptedExceptione){e.printStackTrace();}System.out.println("~~~~~~~~"+newDate());},5,2,TimeUnit.SECONDS);// 延迟5s开始执行任务,第一个任务结束后,间隔2s开始执行第二个任务,不可能存在两个任务同时执行scheduler.scheduleWithFixedDelay(()->{try{TimeUnit.SECONDS.sleep(3);}catch(InterruptedExceptione){e.printStackTrace();}System.out.println("~~~~~~~~"+newDate());},5,2,TimeUnit.SECONDS);}

3、

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 5:29:59

Qwen3-VL-8B快速上手:无需代码基础,10分钟搭建图文对话AI

Qwen3-VL-8B快速上手&#xff1a;无需代码基础&#xff0c;10分钟搭建图文对话AI 1. 为什么选择Qwen3-VL-8B&#xff1f; 想象一下&#xff0c;当你看到一张有趣的图片时&#xff0c;可以直接问AI&#xff1a;"这张图里有什么特别之处&#xff1f;"或者"这个场…

作者头像 李华
网站建设 2026/4/15 17:29:20

FanControl终极指南:Windows风扇智能控制完全攻略

FanControl终极指南&#xff1a;Windows风扇智能控制完全攻略 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trending/fa/Fan…

作者头像 李华
网站建设 2026/4/15 14:02:32

从理论到实践:深入剖析扩散模型条件生成中的Guidance机制

1. 扩散模型条件生成的基本概念 想象一下&#xff0c;你正在教一个完全不懂绘画的小朋友临摹一幅画。如果只说"照着画"&#xff0c;他可能会画出完全不同的东西&#xff1b;但如果明确告诉他"画一只戴帽子的猫"&#xff0c;结果就会准确得多。这就是条件生…

作者头像 李华