今日学习(自律天数:6):面试题目,线程池源码解析,手写简易线程池

126 阅读3分钟

前言

今日鼠鼠我啊,约到一个面试了。虽然是个小公司但是投大公司别人也不理双非啊。QAQ

面试题如下

  • ArrayList和LinkedList底层实现区别 (对于阅读过源码的我来说没什么毛病)
  • JVM堆的内存结构、对象晋升(对于能进行JVM调优的我来说不是问题,今天早上还模拟OOM排查问题来着没想到这么简单)
  • java多线程你是怎么使用的(线程池)
  • 线程池的参数如何进行选取(这里说得不太好 cpu密集型和io密集型来讨论)
  • Spring的生命周期 用了那些设计模式 AOP的实现原理 (阅读过一小部分的spring源码直接拿捏)
  • Redis你用到什么地方(分布式锁和热点数据缓存)
  • 分布式锁的实现(太常规了)
  • 你知道哪些Mysql的存储引擎(随便说说了 提到innodb和mysia就行)
  • innodb索引数据结构(B+)
  • 为什么使用B+(对比B树的优势 最大的就是顺序IO)
  • innodb的事务隔离级别(我深入学习过这块 准备了MVCC机制呢不过他没问)
  • 项目部分

1. 手写简易线程池代码

public class MoXiuThreadPool implements Executor {
    //目前的线程池内任务数量
    private final AtomicInteger ctl = new AtomicInteger(0);
    //核心线程数
    private volatile int corePoolSize;
    //最大线程数
    private volatile int maximumPoolSize;
    //超过核心线程数后会加入这里
    private final BlockingQueue<Runnable> workQueue;

    public MoXiuThreadPool(int corePoolSize, int maximumPoolSize, BlockingQueue<Runnable> workQueue) {
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
    }

    @Override
    public void execute(Runnable command) {
        //获取当前任务数量
        int c = ctl.get();
        //如果小于核心线程数那么直接执行就好
        if (c < corePoolSize) {
            if (!addWorker(command)) {
                reject();
            }
            return;
        }
        //大于和核心线程数得入队
        if (!workQueue.offer(command)) {
            //入队失败的话再试一下是否有任务空缺
            if (!addWorker(command)) {
                //失败策略
                reject();
            }
        }
    }

    private void reject() {
        throw new RuntimeException("执行拒绝策略");
    }
    //执行线程
    private boolean addWorker(Runnable command) {
        if (ctl.get() >= maximumPoolSize) {
            return false;
        }
        Worker worker = new Worker(command);
        worker.thread.start();
        ctl.incrementAndGet();
        return true;
    }

    private final class Worker implements Runnable {
        Thread thread;
        Runnable firstTask;

        public Worker(Runnable runnable) {
            thread = new Thread(this);
            this.firstTask = runnable;
        }

        @Override
        public void run() {
            Runnable task = firstTask;
            try {
                //循环去执行任务
                while (task != null || (task = getTask()) != null) {
                    task.run();
                    if (ctl.get() > maximumPoolSize) {
                        break;
                    }
                    task = null;
                }
            }finally {
                ctl.decrementAndGet();
            }
        }
        //从队列中去拿
        private Runnable getTask() {
            for (; ; ) {
                try {
                    return workQueue.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

以上实现了一个简单的线程池大家可以去跑是没问题的逻辑简单

2. JDK线程池详解

提交任务代码

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    //拿到当前任务数
    int c = ctl.get();
    //判断任务的数量是否小于核心线程数  这里比较烦了本来就是一个32为的in类型数字 李老师非要把前2为拿出来搞出线程池状态维护
    if (workerCountOf(c) < corePoolSize) {
        //执行任务
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    //当前是否为运行状态  是就入队
    if (isRunning(c) && workQueue.offer(command)) {
        //再检查一下是否为运行态
        int recheck = ctl.get();
        if (!isRunning(recheck) && remove(command))
            //不是就拒绝了
            reject(command);
            //如果当前没有任务了
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    else if (!addWorker(command, false))
        reject(command);
}

现在去看核心的执行任务代码

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        //拿任务
        while (task != null || (task = getTask()) != null) {
            w.lock();
            
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                beforeExecute(wt, task);
                Throwable thrown = null;
                try {
                    task.run();
                } catch (RuntimeException x) {
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}

大概就是去拿任务调用任务的run方法执行,今天中午面试没睡午觉所以学习时间不长。今天拉了,明天补回来QAQ.