java基础-多线程
线程的生命周期
ThreadLocal
Thead源码
1 | public class Thread implements Runnable { |
ThreadLocalMap是TreadLocal的内部类
ThreadLocal内存泄漏
ThreadLocalMap 中使用的 key 为 ThreadLocal 的弱引用,而 value 是强引用。所以,如果 ThreadLocal 没有被外部强引用的情况下,在垃圾回收的时候,key 会被清理掉,而 value 不会被清理掉。这样一来,ThreadLocalMap 中就会出现 key 为 null 的 Entry。假如我们不做任何措施的话,value 永远无法被 GC 回收,这个时候就可能会产生内存泄露。ThreadLocalMap 实现中已经考虑了这种情况,在调用 set()、get()、remove() 方法的时候,会清理掉 key 为 null 的记录。使用完 ThreadLocal方法后 最好手动调用remove()方法
1 | static class Entry extends WeakReference<ThreadLocal<?>> { |
锁
volatile
保证了变量和可见性和顺序性,无法保证原子性(如自增操作)
底层利用内存屏障来实现,Unsafe提供了三个内存屏障的类:
1
2
3 public native void loadFence();
public native void storeFence();
public native void fullFence();
synchronized
- 修饰实例方法 (锁当前对象实例)
- 修饰静态方法 (锁当前类)
- 修饰代码块 (锁指定对象/类)
synchronized 同步语句块的实现使用的是 monitorenter 和 monitorexit 指令,其中 monitorenter 指令指向同步代码块的开始位置,monitorexit 指令则指明同步代码块的结束位置。synchronized 修饰的方法并没有 monitorenter 指令和 monitorexit 指令,取得代之的确实是 ACC_SYNCHRONIZED 标识,该标识指明了该方法是一个同步方法。不过两者的本质都是对对象监视器 monitor 的获取。
AQS
核心内容state和CLH(虚拟的双向队列)
自定义同步器实现时主要实现以下几种方法:
- isHeldExclusively():该线程是否正在独占资源。只有用到condition才需要去实现它。
- tryAcquire(int):独占方式。尝试获取资源,成功则返回true,失败则返回false。
- tryRelease(int):独占方式。尝试释放资源,成功则返回true,失败则返回false。
- tryAcquireShared(int):共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
- tryReleaseShared(int):共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回true,否则返回false
Semaphore
限制一定数量的线程执行,内部定义Sync实现AQS,底层使用AQS的state
1 | Semaphore sem = new Semaphore(2); |
CountDownLatch
表示一个线程需要等一批线程执行后才能执行,内部定义Sync实现AQS,底层使用AQS的state,state为一批线程的数量
1 | CountDownLatch latch = new CountDownLatch(10); |
缺点:
- 只能使用一次
CyclicBarrier
表示所有子线程都调用wait后,先执行cyclicBarrier的回调函数,再继续子线程wait后的方法
底层依赖ReentrandLock和Condition,利用ReentrantLock的Condition来阻塞和通知线程;
1 | CyclicBarrier cyclicBarrier = new CyclicBarrier(10,()->{ |
优点:
- 可以循环使用
synchronized 和 volatile 有什么区别?
synchronized 和 ReentrantLock 有什么区别?
- 两者都是可重入锁
- synchronized 依赖于 JVM 而 ReentrantLock 依赖于 API
- ReentrantLock能力更多:等待可中断 ,可实现公平锁,可实现选择性通知(锁可以绑定多个条件)
线程池
Executors工具类(不推荐)
- FixedThreadPool,允许请求的队列长度为 Integer.MAX_VALUE
- SingleThreadExecutor,允许请求的队列长度为 Integer.MAX_VALUE
- CachedThreadPool, 允许创建的线程数量为 Integer.MAX_VALUE
- ScheduledThreadPool, 允许创建的线程数量为 Integer.MAX_VALUE
ThreadPoolExecutor
核心参数
- corePoolSize:核心线程数
- maximumPoolSize:最大线程数,队列中存放的任务达到队列容量的时候才会由新增线程到此数值
- workQueue:等待队列
- keepAliveTime:存活时间,线程池中的线程数量大于 corePoolSize时,超出的线程的存活时间
- unit:存活时间的单位
- threadFactory:可以自定义实现,指定线程组和线程名称前缀
- handler:饱和策略
workQueue
handle
- ThreadPoolExecutor.AbortPolicy:抛出异常直接拒绝(默认)
- ThreadPoolExecutor.CallerRunsPolicy:调用执行自己的线程运行任务
- ThreadPoolExecutor.DiscardPolicy:不处理,直接丢掉
- ThreadPoolExecutor.DiscardOldestPolicy:丢弃最早的未处理的任务请求
线程数数量设置
- CPU 密集型任务(N+1)
- IO 密集型任务(2N)