seamew hai 1 ano
pai
achega
b487815f5b

+ 261 - 3
后端/Java/JAVA高阶/JUC编程/线程池源码.md

@@ -236,7 +236,7 @@ private final class Worker extends AbstractQueuedSynchronizer implements Runnabl
 }
 ```
 
-#### runWorker方法
+### runWorker方法
 
 ```Java
 final void runWorker(Worker w) {
@@ -282,7 +282,7 @@ final void runWorker(Worker w) {
 }
 ```
 
-#### 从任务队列中取出一个任务
+### 从任务队列中取出一个任务
 
 ```Java
 private Runnable getTask() {
@@ -336,7 +336,7 @@ private Runnable getTask() {
 > 3. 线程池线程数大于最大线程数
 > 4. 线程可以被超时回收的情况下等待新任务超时
 
-#### 工作线程退出
+### 工作线程退出
 
 ```Java
 private void processWorkerExit(Worker w, boolean completedAbruptly) {
@@ -377,3 +377,261 @@ private void processWorkerExit(Worker w, boolean completedAbruptly) {
     }
 }
 ```
+
+### 工作线程如何回收
+
+```java
+    private Runnable getTask() {
+        boolean timedOut = false; // Did the last poll() time out?
+
+        for (;;) {
+            int c = ctl.get();
+            int rs = runStateOf(c);
+
+            // Check if queue empty only if necessary.
+            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
+                decrementWorkerCount();
+                return null;
+            }
+
+            int wc = workerCountOf(c);
+
+            // Are workers subject to culling?
+            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
+
+            if ((wc > maximumPoolSize || (timed && timedOut))
+                && (wc > 1 || workQueue.isEmpty())) {
+                if (compareAndDecrementWorkerCount(c))
+                    return null;
+                continue;
+            }
+
+            try {
+                // 通过时间进行判断,如果超时返回false
+                Runnable r = timed ?
+                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
+                    workQueue.take();
+                if (r != null)
+                    return r;
+                timedOut = true;
+            } catch (InterruptedException retry) {
+                timedOut = false;
+            }
+        }
+    }
+
+```
+
+```java
+private void processWorkerExit(Worker w, boolean completedAbruptly) {
+    // 如果completedAbruptly为true则表示任务执行过程中抛出了未处理的异常
+    // 所以还没有正确地减少worker计数,这里需要减少一次worker计数
+    if (completedAbruptly) 
+        decrementWorkerCount();
+
+    final ReentrantLock mainLock = this.mainLock;
+    mainLock.lock();
+    try {
+        // 把将被销毁的线程已完成的任务数累加到线程池的完成任务总数上
+        completedTaskCount += w.completedTasks;
+        // 这段代码就会减少工作线程
+        workers.remove(w); // 从工作线程集合中移除该工作线程
+    } finally {
+        mainLock.unlock();
+    }
+
+    // 尝试结束线程池
+    tryTerminate();
+
+    int c = ctl.get();
+    // 如果是RUNNING 或 SHUTDOWN状态
+    if (runStateLessThan(c, STOP)) {
+        // worker是正常执行完
+        if (!completedAbruptly) {
+            // 如果允许核心线程超时则最小线程数是0,否则最小线程数等于核心线程数
+            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
+            // 如果阻塞队列非空,则至少要有一个线程继续执行剩下的任务
+            if (min == 0 && ! workQueue.isEmpty())
+                min = 1;
+            // 如果当前线程数已经满足最小线程数要求,则不需要再创建替代线程
+            if (workerCountOf(c) >= min)
+                return; // replacement not needed
+        }
+        // 重新创建一个worker来代替被销毁的线程
+        addWorker(null, false);
+    }
+}
+```
+
+##  如何中断
+
+### 中断别人
+
+```java
+private void processWorkerExit(Worker w, boolean completedAbruptly) {
+    // 尝试结束线程池
+    // 这里会中断别人
+    tryTerminate();
+}
+```
+
+### 具体实现
+
+```java
+    final void tryTerminate() {
+        for (;;) {
+            int c = ctl.get();
+            if (isRunning(c) ||
+                runStateAtLeast(c, TIDYING) ||
+                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
+                return;
+            if (workerCountOf(c) != 0) { // Eligible to terminate
+                // 中断 ONLY_ONE = false
+                interruptIdleWorkers(ONLY_ONE);
+                return;
+            }
+
+            final ReentrantLock mainLock = this.mainLock;
+            mainLock.lock();
+            try {
+                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
+                    try {
+                        terminated();
+                    } finally {
+                        ctl.set(ctlOf(TERMINATED, 0));
+                        termination.signalAll();
+                    }
+                    return;
+                }
+            } finally {
+                mainLock.unlock();
+            }
+            // else retry on failed CAS
+        }
+    }
+```
+
+```java
+    private void interruptIdleWorkers(boolean onlyOne) {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            for (Worker w : workers) {
+                Thread t = w.thread;
+                if (!t.isInterrupted() && w.tryLock()) {
+                    try {
+                        // 前面已经被中断了,中断别人,相当于链式的中断
+                        t.interrupt();
+                    } catch (SecurityException ignore) {
+                    } finally {
+                        w.unlock();
+                    }
+                }
+                if (onlyOne)
+                    break;
+            }
+        } finally {
+            mainLock.unlock();
+        }
+    }
+```
+
+### 唤醒
+
+```java
+    private Runnable getTask() {
+        boolean timedOut = false; // Did the last poll() time out?
+
+        for (;;) {
+            int c = ctl.get();
+            int rs = runStateOf(c);
+
+            // Check if queue empty only if necessary.
+            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
+                decrementWorkerCount();
+                return null;
+            }
+
+            int wc = workerCountOf(c);
+
+            // Are workers subject to culling?
+            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
+
+            if ((wc > maximumPoolSize || (timed && timedOut))
+                && (wc > 1 || workQueue.isEmpty())) {
+                if (compareAndDecrementWorkerCount(c))
+                    return null;
+                continue;
+            }
+
+            try {
+                // 抛出异常会重置状态
+                Runnable r = timed ?
+                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
+                    workQueue.take();
+                if (r != null)
+                    return r;
+                timedOut = true;
+            } catch (InterruptedException retry) {
+                timedOut = false;
+            }
+        }
+    }
+```
+
+### 如果直接使用shutdown函数
+
+> 如果线程被中断会立即停止该线程在执行的任务吗?
+>
+> interrupt() 方法并不像在 for 循环语句中使用 break 语句那样干脆,马上就停止循环。调用 interrupt() 方法仅仅是在当前线程中打一个停止的标记,并不是真的停止线程。
+
+1. Running 状态,任务已全部完成,线程在阻塞等待。在 Running 状态进入 shutdown 状态。
+
+很简单,中断信号将其唤醒,从而进入下一轮循环。到达条件1处,符合条件,减少工作线程数量,并返回null,由外层结束这条线程。这里的decrementWorkerCount()是自旋式的,一定会减1
+
+2. Running 状态,任务还没有完全执行完
+
+```java
+Runnable r = timed ?
+    // 内部的方法
+    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
+    workQueue.take();
+```
+
+```java
+    public E take() throws InterruptedException {
+        E x;
+        int c = -1;
+        final AtomicInteger count = this.count;
+        final ReentrantLock takeLock = this.takeLock;
+        // 中断获取锁
+        takeLock.lockInterruptibly();
+        try {
+            while (count.get() == 0) {
+                notEmpty.await();
+            }
+            x = dequeue();
+            c = count.getAndDecrement();
+            if (c > 1)
+                notEmpty.signal();
+        } finally {
+            takeLock.unlock();
+        }
+        if (c == capacity)
+            signalNotFull();
+        return x;
+    }
+
+    public void lockInterruptibly() throws InterruptedException {
+        sync.acquireInterruptibly(1);
+    }
+
+    public final void acquireInterruptibly(int arg)
+            throws InterruptedException {
+        // 重置中断状态
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        if (!tryAcquire(arg))
+            doAcquireInterruptibly(arg);
+    }
+```

BIN=BIN
算法/排序算法/assets/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMTUyMDUy,size_16,color_FFFFFF,t_70.png


+ 50 - 0
算法/排序算法/基本排序算法.md

@@ -1,3 +1,5 @@
+![在这里插入图片描述](assets/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMTUyMDUy,size_16,color_FFFFFF,t_70.png)
+
 # 归并排序
 
 ```cpp
@@ -82,3 +84,51 @@ int main() {
 }
 ```
 
+# 堆排序
+
+```cpp
+#include <bits/stdc++.h>
+
+using namespace std;
+
+void adjust(vector<int>& nums, int start, int end) {
+    int tmp = nums[start];
+    for (int i = 2 * start + 1; i <= end; i = i * 2 + 1) {
+        // 有右孩子并且左孩子小于右孩子
+        if (i < end && nums[i] < nums[i + 1]) {
+            i++;
+        }
+        // i一定是左右孩子的最大值
+        if (nums[i] > tmp) {
+            nums[start] = nums[i];
+            start = i;
+        } else {
+            // 比左右孩子都大
+            break;
+        }
+    }
+    nums[start] = tmp;
+}
+
+void heapSort(vector<int>& nums) {
+    int len = (int) nums.size();
+    // 第一次建立大根堆,从后往前依次调整
+    for (int i = (len - 1 - 1) / 2; i >= 0; i--) {
+        adjust(nums, i, len - 1);
+    }
+    // 每次将根和待排序的最后一次交换,然后在调整
+    int tmp;
+    for (int i = 0; i < len - 1; i++) {
+        swap(nums[0], nums[len - i - 1]);
+        adjust(nums, 0, len - 1 - i - 1);
+    }
+}
+
+int main() {
+    vector<int> nums = {9, 5, 6, 3, 5, 3, 1, 0, 96, 66};
+    heapSort(nums);
+    for (auto num: nums) cout << num << " ";
+    return 0;
+}
+```
+

BIN=BIN
论文/assets/image-20230816145833671.png


BIN=BIN
论文/assets/image-20230816145844068.png


BIN=BIN
论文/assets/image-20230816145853300.png


BIN=BIN
论文/assets/image-20230816153747750.png


+ 11 - 0
论文/petri网.md

@@ -0,0 +1,11 @@
+![image-20230816145833671](assets/image-20230816145833671.png)
+
+![image-20230816145844068](assets/image-20230816145844068.png)
+
+![image-20230816145853300](assets/image-20230816145853300.png)
+
+单纯网:没有自旋
+
+简单网:没有环
+
+![image-20230816153747750](assets/image-20230816153747750.png)

+ 6 - 0
面经/问答/Mysql.md

@@ -41,6 +41,12 @@
 
 3. InnoDB 存储引擎:InnoDB 是 MySQL 的一种常用存储引擎,它使用了多版本并发控制(MVCC)和行级锁来实现高并发性和事务支持。InnoDB 存储引擎的核心数据结构包括页(page)、记录(record)、索引(index)和事务日志(transaction log)等。
 
+## nysql低层文件结构
+
+- db.opt,用来存储当前数据库的默认字符集和字符校验规则。
+- t_order.frm ,t_order 的**表结构**会保存在这个文件。在 MySQL 中建立一张表都会生成一个.frm 文件,该文件是用来保存每个表的元数据信息的,主要包含表结构定义。
+- t_order.ibd,t_order 的**表数据**会保存在这个文件。表数据既可以存在共享表空间文件(文件名:ibdata1)里,也可以存放在独占表空间文件(文件名:表名字.ibd)。这个行为是由参数 innodb_file_per_table 控制的,若设置了参数 innodb_file_per_table 为 1,则会将存储的数据、索引等信息单独存储在一个独占表空间,从 MySQL 5.6.6 版本开始,它的默认值就是 1 了,因此从这个版本之后, MySQL 中每一张表的数据都存放在一个独立的 .ibd 文件。
+
 ## 联合索引定义要注意哪些点
 
 在 MySQL 中定义联合索引时,需要注意以下几点:

+ 1 - 0
面经/问答/spring.md

@@ -85,6 +85,7 @@ Spring 框架中的 Bean 是否线程安全,取决于其作用域和状态。
 2. **@Import(AutoConfigurationImportSelector.class)**——核心注解
 
 * 该注解通过`@Import`注解导入`AutoConfigurationImportSelector`,这个类实现了一个导入器接口`ImportSelector`。在该接口中存在一个方法`selectImports`,
+* 通过与BeanClassLoaderAware结合注入bean
 
 ## SpringBoot启动流程
 

+ 12 - 1
面经/项目/项目.md

@@ -59,4 +59,15 @@ CPU标高:TOP命令
 
 * batch insert
 * 导致事务注解失效
-* SPI
+* SPI
+
+## 职业规划
+
+作为应届生加入xxx。希望能在这个大平台,能够相周围优秀的同事们学习,学习xxx的文化,通过追赶他们,让自己成为一个更加职业化,专业化的人。在公司工作一段时间后希望可以独立承担公司业务,(事业心+好心态+稳定)
+
+* 入职 1 年,熟悉工作情况,在努力学习本职工作相关知识的同时学习业务相关的知识,积极参加团队活动,与同事和谐相处
+
+* 入职2-3年,精进业务水平,在稳定提升的基础上做到独当一面,保证完成日常工作的同时汇总工作经验
+
+* 入职3-5年,在总结经验的基础上产出方法论,积极与同事、上级交流沟通,助力培养部门设计学习进步氛围,提升产品的体验竞争力
+