import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor.AbortPolicy;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Auther: 范子祺
 * @Date: ${DATE} ${HOUR}:${MINUTE}
 * @Description:
 */
public class Main {
    public static void main(String[] args){
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor
                (10, 15, 1,
                TimeUnit.SECONDS, new ArrayBlockingQueue<>(100),
                Executors.defaultThreadFactory(), new AbortPolicy());
        // 源码学习
        threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("test");
            }
        });
        // 上下对比, 区别,应用
        threadPoolExecutor.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("submit" +
                        "");
            }
        });

        ReentrantLock reentrantLock = new ReentrantLock(true);
        reentrantLock.lock();
        try {
        }finally {
            reentrantLock.unlock();
        }

    }
}

几个问题
1 如何添加线程。 cas+ lock
2 线程如何保活。 钩子+processWorkerExit,启动新工人,可以理解为忘记错误重头再来。
3 线程如何回收。 while + decrementWorkerCount
4 自旋是如何实现的。 cas, 在增加工人数量的时候使用了

threadPoolExecutor.execute( 方法分析
1 将要执行的任务往线程池丢
2 获得线程池状态ctl, 运行状态,池内运行线程数量
3 如果小于核心线程数量, 将任务添加 workerCountOf(c) < corePoolSize
3.1 添加 核心线程数
开始for
如果线程池状态 >= shutdown- 返回false,exit for
否则进入下一个for
获得 线程池 线程数量
如果线程池线程数量 大于 线程池计算的最大容量 或者 大于核心线程数 返回false,exit for
否则,compareAndIncrementWorkerCount 添加ctl的核心线程数,数+1 使用了cas,添加成功,退出自旋,退出for
继续开始try,用传入的任务丢到worker,worker中向线程池中新增线程,并将这个任务丢给这个新创的线程了
拿到work加入池子的线程, 加锁ReentrantLock (这里用了aqs)。这里加锁的原因是:我们准备让这个新加到线程池的线程开始工作,但这个时候,我们要保证整个操作的原子性。所以加锁。
开始try 拿到线程池的状态 如果状态小于shutdown,但是这个新建的线程却已经活了,直接抛异常后面有finally解决。如果正常,则将worker添加到线程池的workers中,接着比较一下运行时候线程池最多时候的数量,记录最大值。 标记,workeraddsuccess,然后解锁,接着启动这个线程,标记workerstarted-success,最后
如果启动失败了,进入减worker方法,里面也会加锁解锁,如果返回 添加成功了
直接return,execute执行成功。

8 8 8 0001 1101 coun-bit 29
8 8 8 0000 0001 1
0010 000 8 8 8 1 << 29
0001 111 8-1 8-1 8-1 1 << 29 -1 CAPACITY
1110 000 8 8 8 ~CAPACITY
8-1 8-1 8-1 8-1 -1

说白了, 就是一个食堂,三个正式工打菜,还有三个临时工,然手呢, 正式工先干,后面来的人先排队,队伍都排不下了, 就让临时工上,临时工也上完了这时候就开始执行拒绝策略。所以拒绝的时候嗯,先在可以研究线程池的其他细节部分了。
然后里面通过钩子啊, while啊,等方式保持线程数不变一直跑。跑到阿姨下班食堂关门。
https://blog.csdn.net/m0_67698950/article/details/124042501 --- 线程池相关源码。 runnable和futuretask对比
https://blog.csdn.net/weixin_46097842/article/details/125085449 --- 有张流程图可看看
https://blog.csdn.net/dengjili/article/details/100171491 --源码中的二进制


泛型基础练习
https://blog.csdn.net/Beyondczn/article/details/107093693
b占sp
bilibili.com/video/BV1xJ411n77R?p=13&spm_id_from=pageDriver&vd_source=562955621af926e4655ded0199c26c61


什么叫适应性自旋: 自旋的时间是一个根据环境产生的动态时间,就像 适应性吃饭, 我们在家在学校在工作吃饭的时间一样。

aqs abstractqueuedsynchronizer
reentranlock
在使用阻塞等待获取锁的方式中,必须在try代码块之外,并且在加锁方法与try代码块之间没有任何可能抛出异常的方法调用,避免加锁成功后,在finally中无法解锁。
说明一:如果在lock方法与try代码块之间的方法调用抛出异常,那么无法解锁,造成其它线程无法成功获取锁。
说明二:如果lock方法在try代码块之内,可能由于其它方法抛出异常,导致在finally代码块中,unlock对未加锁的对象解锁,它会调用AQS的tryRelease方法(取决于具体实现类),抛出IllegalMonitorStateException异常。
说明三:在Lock对象的lock方法实现中可能抛出unchecked异常,产生的后果与说明二相同。 java.concurrent.LockShouldWithTryFinallyRule.rule.desc
aqs的源码---适合熟悉后跟着看
https://www.bilibili.com/video/BV1Zz4y197iF/?spm_id_from=333.337.search-card.all.click&vd_source=562955621af926e4655ded0199c26c61

aqs 公众号文章,看的我要睡觉了----需要多啃几遍
https://javadoop.com/post/AbstractQueuedSynchronizer


共享锁和独占锁