多线程(持续更新中)

线程池 Doug Lea

  1. 普通线程池
  2. 定时线程池

ThreadPoolExecutor

构造方法参数:

corePoolSize :池中所保存的线程数,包括空闲线程
• maximumPoolSize:池中允许的最大线程数
• keepAliveTime: 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间
• unit:keepAliveTime 参数的时间单位
• workQueue :执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务
• threadFactory:执行程序创建新线程时使用的工厂
• handler :由于超出线程范围和队列容量而使执行
submit方法:

  1. 小于核心
    addWork
  2. 大于核心
  3. 直接增加任务
  4. 如果3增加失败 就拒绝
    拒绝策略

    线程池有四种拒绝策略:
    AbortPolicy:抛出异常,默认
    CallerRunsPolicy:不使用线程池执行
    DiscardPolicy:直接丢弃任务
    DiscardOldestPolicy:丢弃队列中最旧的任务 对 于 线 程 池 选 择 的 拒 绝 策 略 可 以 通 过 RejectedExecutionHandler handler = new
    ThreadPoolExecutor.CallerRunsPolicy();来设置。
    Jps>jstack
    jstack 是排查线程死锁

Submit&futuretask方法区别

  1. 有无返回值
  2. Task不一样 futuretask一个task本身

CAS中有乐观锁思想及实现

多线程中的三个关键字

  • 原子性
  • 可见性
  • 有序性
    java层面关键字解决上述三个问题:
  • volatile: 保证可见性、有序性
    ⚫保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
    ⚫ 禁止进行指令重排序。
  • synchronized:重量级锁、重(chong)入锁
    ⚫ 对于普通同步方法,锁是当前实例对象。
    ⚫ 对于静态同步方法,锁是当前类的 Class 对象。
    ⚫ 对于同步方法块,锁是 Synchonized 括号里配置的对象。
    方法中:ACC_SYNCHRONIZED、代码块:monitorenter monitorexit
    lock锁:
  • ReentrantLock 重入锁: 手动,lock指令,比synchornized更加灵活
    Condition适用于生产者消费者模型
  • ReentrantReadWriteLock 读写锁
    jdk1.8之后Stamped Lock
try{
  //上锁
  lock.lock();
  ...
}finally{
  //解锁
  lock.unlock();
}

方法

void lock() 获取锁,调用该方法当前线程将会获取锁,当锁获取后,该方法将返回。
• void lockInterruptibly() throws InterruptedException 可中断获取锁,与 lock()方法不同之处在于该方
法会响应中断,即在锁的获取过程中可以中断当前线程
• boolean tryLock() 尝试非阻塞的获取锁,调用该方法立即返回,true 表示获取到锁
• boolean tryLock(long time,TimeUnit unit) throws InterruptedException 超时获取锁,以下情况会返回:
时间内获取到了锁,时间内被中断,时间到了没有获取到锁。
• void unlock() 释放锁

统计:
java.util.concurrent.locks.ReentrantLock#getHoldCount
java.util.concurrent.locks.ReentrantLock#getQueuedThreads
  • ReentrantReadWriteLock 读写锁
    细粒度问题 ,读是共享的、写是独占的
    java8 增加了对读写锁的优化:StampedLock
  • AbstractQueuedSynchronizer 队列同步器
java.util.concurrent.locks.AbstractQueuedSynchronizer#acquire 独占式获取同步状态
java.util.concurrent.locks.AbstractQueuedSynchronizer#acquireInterruptibly 独占式获取同步状态,未获取可以
中断
java.util.concurrent.locks.AbstractQueuedSynchronizer#acquireShared 共享式获取同步状态
java.util.concurrent.locks.AbstractQueuedSynchronizer#acquireSharedInterruptibly 共享式获取同步状态,未获
取可以中断
java.util.concurrent.locks.AbstractQueuedSynchronizer#release 独占释放锁
java.util.concurrent.locks.AbstractQueuedSynchronizer#releaseShared 共享式释放锁
  • CountDownLatch (同步工具类)
    CountDownLatch 时,需要指定一个整数值,此值是线程将要等待的操作数。当某个线程为了要执行这些操作而等待时,需要调用 await 方法。await 方法让线程进入休眠状态直到所有等待的操作完成为止。当等待
    的某个操作执行完成,它使用 countDown 方法来减少 CountDownLatch 类的内部计数器。当内部计数器递减为 0 时,CountDownLatch 会唤醒所有调用 await 方法而休眠的线程们。
⚫ java.util.concurrent.CountDownLatch#await()
⚫ java.util.concurrent.CountDownLatch#countDown()
⚫ java.util.concurrent.CountDownLatch#getCount()

原理
CountDownLatch 的构造函数接收一个 int 类型的参数作为计数器,如果你想等待 N 个点完成,这里就传入 N。
当我们调用 CountDownLatch 的 countDown 方法时,N 就会减 1,CountDownLatch 的 await 方法会阻塞当前线程,直到 N 变成零。由于 countDown 方法可以用在任何地方,所以这里说的 N 个点,可以是 N 个线程,也可以是 1 个线程里的 N 个执行步骤。用在多个线程时,只需要把这个CountDownLatch 的引用传递到线程里即可。CountDownLatch 是一次性的,只能通过构造方法设置初始计数量,计数完了无法进行复位,不能达到复用。

  • Semaphore (信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。
java.util.concurrent.Semaphore#acquire() 获取许可
java.util.concurrent.Semaphore#release() 释放许可
java.util.concurrent.Semaphore#tryAcquire() 尝试获取许可

雪花算法

HashMap

如何优化扩容?
估算大小,初始设定
ReentrantLock

发布了7 篇原创文章 · 获赞 0 · 访问量 106

猜你喜欢

转载自blog.csdn.net/weixin_44188300/article/details/103758949