一、Semaphore 信号量
如果线程中用到semaphore ,并且此时达到了semaphore限制的最大数量,线程堵塞,只要其他线程释放了,才能继续运行。
二、countDownLatch
类似于一个计数器,初始值是线程的数量,线程运行完,countdownlatch-1,直到为0,才继续运行。
三、CyclicBarrier
类似一个计数器,等到所有用CyclicBarrier的线程到达某个点后,继续向下执行。可以再等到所有用CyclicBarrier的线程到达某个点后,继续向下执行。如此循环
使用future的实现类futureTask实现多线程去除重复计算的问题
把逻辑都放到futureTask里面,把futureTask放到concurrentMap里面,然后再调用futureTask run方法,相同的key获取的同一个futureTask类, futureTask的run方法多次调用只会执行一次
四、Java线程池:
1.线程池基本运行原理:线程首先占满核心数,然后占满队列数量,然后占满最大线程数量,如果都满了就执行抛弃策略。
2.线程池如何复用线程:接收runnable类,封装runnable成另一个runnable,然后放到Thread类里,封装的runnable用一次,Thread复用。
3. java中一个int占4个字节1字节=8bit 1bit等于一个二进制位
(假定推论:原子类可以存字节)
线程池用一个原子类存储线程池和状态,总共一个int 所占bit的大小,高3位存状态,低29位为线程数量。
线程数量增加原子类增加,减少,原子类减少。
//CAS,无锁并发 原子类
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//表示线程池线程数的bit数
private static final int COUNT_BITS = Integer.SIZE - 3;
//最大的线程数量,数量是完全够用了
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
原子类状态:
// runState is stored in the high-order bits
//1110 0000 0000 0000 0000 0000 0000 0000(很耿直的我)
private static final int RUNNING = -1 << COUNT_BITS;
//0000 0000 0000 0000 0000 0000 0000 0000(很耿直的我)
private static final int SHUTDOWN = 0 << COUNT_BITS;
//0010 0000 0000 0000 0000 0000 0000 0000(很耿直的我)
private static final int STOP = 1 << COUNT_BITS;
//0100 0000 0000 0000 0000 0000 0000 0000(很耿直的我)
private static final int TIDYING = 2 << COUNT_BITS;
//0110 0000 0000 0000 0000 0000 0000 0000(很耿直的我)
private static final int TERMINATED = 3 << COUNT_BITS;
获取线程池的状态:
// private static int runStateOf(int c) { return c & ~CAPACITY; }
//获取线程的数量
private static int workerCountOf(int c) { return c & CAPACITY; }
//组装状态和数量,成为ctl
private static int ctlOf(int rs, int wc) { return rs | wc; }
注释:1>
& 任何与0& 结果都为0 ,1&1为 ,~CAPACITY 类似于取补码的意思 0011 取反为1100。CAPACITY 大概为0001111111.... ~ CAPACITY为11100000...。11100000....与ctl&可以得到高位数。CAPACITY为0001111111...与ctl&可以得到低位数。
2>
| 任何与 1|运算结果都为1,高三位数例如11100000与0000000结果就是高三位与低29位合并成为ctl
猜想———>修改线程池状态:首先取出线程数量然后在和状态常量做|(合并)运算。
五、future 有返回值的线程应该是可以放到线程池或者thread里面。
FutureTask---》future ,
Future包含Callable
使用future解决多线程重复计算的问题
- 创建缓存
- 根据入参生成key值,根据key,判断缓存中有没有对应的future
- 如果没有 传进future并且把计算逻辑放到future里面。
- 执行futuren 的run方法。(同一个future,多次调用也只会执行一次)