leecodecode【面试150】【2026.7.6打卡-java版本】
最大子数组和要点动态规划class Solution { public int maxSubArray(int[] nums) { //只要不是小于0的都加 int[] dp new int[nums.length]; dp[0] nums[0]; int max dp[0]; for(int i 1; i nums.length; i){ dp[i] Math.max(dp[i-1],0) nums[i]; max Math.max(dp[i],max); } return max; } }环形子数组的最大和要点参考上面但是要记录最少和最多class Solution { public int maxSubarraySumCircular(int[] nums) { int maxp nums[0]; int maxAns nums[0]; int minp nums[0]; int minAns nums[0]; int total nums[0]; for(int i 1; i nums.length; i){ int num nums[i]; maxp Math.max(maxp,0)num; maxAns Math.max(maxp, maxAns); minp Math.min(minp,0) num; minAns Math.min(minp, minAns); total num; } if(maxAns 0){ return maxAns; } return Math.max(maxAns, total - minAns); } }数组中的第K个最大元素要点排序方法一快速排序class Solution { public int findKthLargest(int[] nums, int k) { //快排 int target nums.length - k ; kuaipai(nums, 0, nums.length -1, target); return nums[target]; } public void kuaipai(int[] nums, int left, int right, int target){ if(left right){ return ; } int mid left (right - left)/2; int mubiao nums[mid]; int l left; int r right; while(l r){ while(nums[l] mubiao ){ l; } while(nums[r] mubiao){ r--; } if(l r){ int temp nums[l]; nums[l] nums[r]; nums[r] temp; l; r--; } } if(target r){ kuaipai(nums, left, r,target); }else if(target l){ kuaipai(nums, l, right, target); } } }方法2 堆排序class Solution { public int findKthLargest(int[] nums, int k) { // 小顶堆默认就是升序堆顶最小 PriorityQueueInteger minHeap new PriorityQueue(k); for (int num : nums) { if (minHeap.size() k) { minHeap.offer(num); } else if (num minHeap.peek()) { // 当前元素比堆顶大替换堆顶 minHeap.poll(); minHeap.offer(num); } } return minHeap.peek(); } }不用内置函数class Solution { public int findKthLargest(int[] nums, int k) { // 1. 用前 k 个元素构建一个小顶堆数组表示 int[] heap new int[k]; for (int i 0; i k; i) heap[i] nums[i]; // 建堆从最后一个非叶子节点开始下沉 for (int i k / 2 - 1; i 0; i--) sink(heap, i, k); // 2. 遍历剩余元素 for (int i k; i nums.length; i) { if (nums[i] heap[0]) { // 大于堆顶则替换 heap[0] nums[i]; sink(heap, 0, k); } } return heap[0]; } // 下沉调整小顶堆 private void sink(int[] heap, int i, int n) { while (2 * i 1 n) { int j 2 * i 1; if (j 1 n heap[j 1] heap[j]) j; // 选较小的孩子 if (heap[i] heap[j]) break; swap(heap, i, j); i j; } } private void swap(int[] arr, int i, int j) { int tmp arr[i]; arr[i] arr[j]; arr[j] tmp; } }二进制求和要点模拟class Solution { public String addBinary(String a, String b) { //模拟 int i a.length() -1; int j b.length() -1; StringBuilder ans new StringBuilder(); int carry 0; while(i 0 || j 0 || carry 0){ int s1 i 0 ? a.charAt(i) -0 : 0; int s2 j 0 ? b.charAt(j) -0 : 0; i--; j--; int temp (s1s2 carry)%2; ans.append(temp); carry (s1 s2 carry)/2; } return ans.reverse().toString(); } }随机知识 Java 并发 锁底层原理 · 深度学习笔记一、基础概念1.1 线程创建方式方式本质特点继承 Thread重写 run()单继承局限不推荐实现 Runnable实现 run()任务与线程解耦无返回值实现 Callable实现 call()有返回值可抛异常线程池复用线程生产环境唯一指定虚拟线程JDK 21轻量级线程不需池化IO密集场景1.2 线程的 6 种状态textNEW → RUNNABLE ←→ BLOCKED / WAITING / TIMED_WAITING → TERMINATED核心记忆RUNNABLE包含 OS 的 Ready Running。sleep()不释放锁wait()释放锁。yield()不改变状态。1.3 线程池核心流程text提交任务 → 当前线程数 corePoolSize → 新建核心线程 → 尝试入队workQueue.offer → 队列满 → 当前线程数 maximumPoolSize → 新建非核心线程 → 最大线程也满 → 触发拒绝策略七大核心参数corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler1.4 execute() vs submit()对比点execute()submit()参数Runnable 只能Runnable / Callable 都可返回值无Future异常直接抛出被 Future 包装需 get() 才可见底层线程池调度入口包装成 FutureTask 后调用 execute()生产红线submit()后不调get()→ 异常静默丢失二、线程本地变量 ThreadLocal2.1 核心原理java// 每个线程内部都有一个 ThreadLocalMap ThreadLocalMap map Thread.currentThread().threadLocals; // Key ThreadLocal 对象弱引用Value 存储的值 map.set(this, value);2.2 内存泄漏Key是弱引用ThreadLocal对象被 GC 时Key 变为 nullValue是强引用若线程长期存活线程池Value 永远无法回收 → 内存泄漏java// ✅ 标准写法finally 中 remove try { threadLocal.set(value); // ... 业务逻辑 ... } finally { threadLocal.remove(); // 救命稻草 }三、阻塞队列BlockingQueue3.1 分类对比队列数据结构是否有界特点ArrayBlockingQueue数组有界生产消费共用一把锁LinkedBlockingQueue链表默认无界生产消费两把锁吞吐量更高SynchronousQueue无存储容量 0不存元素必须交接PriorityBlockingQueue堆无界按优先级出队DelayQueue堆无界延迟到期才能取出3.2 SynchronousQueue 的本质容量为 0不存储任何任务生产者必须等到有消费者线程来接手newCachedThreadPool默认使用 → 没空闲线程就无限创建新线程 → 高并发下可能 OOM四、AQSAbstractQueuedSynchronizer4.1 什么是 AQSJUC 包的基石一个用于构建锁和同步器的框架。核心三要素volatile int state同步状态资源标记CLH 双向链表队列管理等待线程LockSupport.park()/unpark()线程阻塞与唤醒原语两种模式独占模式ReentrantLock同一时刻只能一个线程共享模式CountDownLatch、Semaphore多个线程可同时4.2 模板方法模式AQS 规定好“排队、阻塞、唤醒”的骨架把“尝试获取/释放锁”留给子类实现tryAcquire/tryRelease。五、锁机制核心重点5.1 synchronized vs ReentrantLock对比维度synchronizedReentrantLock实现层级JVM 内置C ObjectMonitorJava APIAQS锁对象隐式this / Class显式new 出来的对象获取/释放自动手动lock/unlock可中断❌ 不可中断✅ lockInterruptibly()超时获取❌ 不支持✅ tryLock(timeout)尝试获取❌ 只能死等✅ tryLock() 立即返回公平锁❌ 非公平✅ 可构造公平锁条件队列单一 WaitSet多个 Condition精准唤醒5.2 锁与资源的关系核心认知锁对象和它保护的资源如count变量在 JVM 底层没有任何强制关联锁保护的是临界区代码块不是变量本身数据安全靠编程约定所有修改共享资源的代码必须走同一把锁如果有人绕过锁直接修改锁形同虚设5.3 ReentrantLock 的公平锁 vs 非公平锁FairSyncNonfairSynclock()直接入队先 CAS 抢一把失败再入队tryAcquire()检查hasQueuedPredecessors()直接 CAS不检查队列吞吐量相对低相对高线程饥饿无可能默认非公平锁的原因减少线程挂起/唤醒的开销提高整体吞吐量。5.4 Monitor监视器只有synchronized才有 JVM 内置的ObjectMonitorObjectMonitor核心结构HotSpot CcppObjectMonitor { _owner; // 当前持有锁的线程 _count; // 重入计数器 _EntryList; // 同步队列等待获取锁 _WaitSet; // 等待队列调用 wait() }每个对象都有 Monitor 吗不每个对象都有对象头Mark Word但 Monitor 是按需创建的只在锁膨胀为重量级锁时才创建。锁升级路径text无锁 → 偏向锁 → 轻量级锁自旋 → 重量级锁Monitor偏向锁Mark Word 存线程 ID无 CAS轻量级锁CAS 自旋用户态不挂起线程重量级锁Mark Word 指向 ObjectMonitor线程挂起涉及内核态六、CountDownLatch门闩Latch机制计数器归零前调用await()的线程阻塞。javaCountDownLatch latch new CountDownLatch(3); latch.await(); // 等待计数器归零 latch.countDown(); // 计数器减 1必须放 finally⚠️ 生产红线countDown()必须放在finally中否则异常导致主线程永久阻塞await()必须设超时await(5, TimeUnit.SECONDS)防止线程挂死不能复用计数器归零后失效需复用请用CyclicBarrier七、Condition.await() 详解使用前提必须持有ReentrantLock否则抛IllegalMonitorStateException。执行流程当前线程封装成 Node加入 Condition 条件队列完全释放锁state置 0LockSupport.park(this)阻塞被signal()唤醒后从条件队列转移到 CLH 同步队列通过acquireQueued重新抢锁抢到后继续执行⚠️ while 循环防虚假唤醒java// ❌ 错误写法 if (队列满) condition.await(); 放入元素(); // ✅ 正确写法 while (队列满) condition.await(); 放入元素();虚假唤醒Spurious Wakeup操作系统或 JVM 可能在没有signal()时唤醒线程。while确保唤醒后重新检查条件。八、Lock 的高级获取方法方法行为响应中断lock()死等直到获取锁❌tryLock()瞬间返回抢到 true没抢到 false非阻塞—tryLock(timeout)限时等待超时返回 false✅lockInterruptibly()死等但等待中可被中断✅用途场景tryLock()非核心任务如清理缓存抢不到就放弃tryLock(timeout)核心任务限时降级如支付接口熔断lockInterruptibly()优雅停机、可取消任务九、核心认知 · 锁的本质锁到底是什么锁就是堆内存中的一个普通对象lock实例 或this里面存了一个数字state或Mark Word。“抢锁”就是多个线程去修改那个数字谁修改成功了CAS谁就获得了锁对象的使用权。关键理解链条text锁对象堆内存中的对象 → 内部有 state / Mark Word → 线程通过 CAS 修改它 → 修改成功 获得锁 → 修改失败 入队阻塞 → 释放锁 把数字改回去 → 唤醒队列中的下一个线程这个认知链条适用于synchronized和ReentrantLock只是底层实现ObjectMonitor vs AQS不同。 总结 · 面试高频金句synchronized vs Lock“synchronized是 JVM 的傻瓜式锁自动释放Lock是 API 级手动锁灵活但必须finally unlock。”锁与资源的关系“锁保护的不是变量而是临界区代码块。数据安全靠编程约定——所有人都走同一把锁。”AQS 的本质“AQS 是 JUC 的基石通过state CLH 队列 park/unpark管理线程排队。”Monitor 的本质“Monitor 是synchronized的重量级锁实现按需创建于锁膨胀时每个 Java 对象不一定有 Monitor。”await 的本质“await() 线程在那一行被冻住直到被countDown()或signal()解冻。”碎碎念后续会更新每天学习的八股和算法 题开始准备秋招的第57天。努力连续更新100天以后每天就按秋招项目【java agent】科研必做项目算法八股锻炼身体来总结。总结25分钟番茄时钟学习法非常不错重新看八股了比起前几天今天效率还可以加油加油1.算法面试150 112/150 2h2.秋招项目【java 项目】【agent 项目 】3.科研要跑一下4.实习7h6.背八股2h7.锻炼身体总结背背背

相关新闻