【Java】多线程精简笔记

  • 进程和线程
    • 进程是系统资源分配的基本单位,线程是系统调度的基本单位
    • 进程是程序正在运行的实例,里面包含着线程
    • 进程有独立的内存和资源,线程共用内存(工作内存独有,主内存共用)和资源
    • 线程比进程更加轻量,线程们共用上下文
  • 并行和并发
    • 并行:多个CPU处理多个线程
    • 并发:一个CPU轮询处理多个线程
  • 线程类Thread的基本属性

  • 优先级:被CPU处理的概率更高
  • 后台线程:后台线程结束后,JVM才结束运行
  • 线程的创建方法
    • 继承Thread类
    • 实现Runnable接口
    • 实现Callable接口
    • lambda表达式创建线程的匿名类对象
  • Runnable和Callable的区别
    • 前者没有返回值,后者有返回值
    • 前者不能抛出异常,后者可以抛出异常
  • Thread的常用方法
方法类型介绍
run()实例线程执行逻辑
start实例启动线程
currentThread()类方法获得当前线程对象引用
join()实例不释放锁,被打断后会恢复至不中断,需捕获异常再次中断
sleep()类方法不释放锁,被打断后会恢复至不中断,需捕获异常再次中断
isInterrupted()实例仅判断线程是不是中断
interrupt()实例中断线程,等待和阻塞的会报异常
interrupted()类方法判断是不是处于中断状态,会恢复中断状态至不中断
  • Object类里,与线程相关的方法
方法类型介绍
wait()实例会释放锁,打断后不恢复
notify()实例唤醒一个等待此对象的线程
notifyAll()实例唤醒所有等待此对象的线程
  • run和start的区别
    • run是线程对象的实例方法,使用run就是正常的调用对象方法,而不是启动线程
    • start就是启动线程并且执行run方法
  • notify和notifyAll的区别
    • notify是随机唤醒一个
    • notifyAll是全部唤醒
  • sleep和wite的区别
    • wite是Object的实例方法,sleep是Thread的类方法
    • sleep和wite被打断抛出的异常不同
    • sleep被打断后会恢复至不打断,需捕获异常再次中断
    • wait会释放锁让出CPU,sleep不会
  • 如何停止一个线程
    • volatile修饰的标志量
    • interrupt()直接打断,会报异常
  • 如何让线程有顺序的执行
    • 使用线程的join方法
    • 使用主线程的join方法
    • 使用线程的wait方法
    • 使用线程的线程池方法
    • 使用线程的Condition(条件变量)方法
    • 使用线程的CountDownLatch(倒计数)方法
    • 使用线程的CyclicBarrier(回环栅栏)方法
    • 使用线程的Semaphore(信号量)方法
  • 线程之间如何通讯
    • 线程通讯指的是多个线程之间通过共享内存或消息传递等方式来协调和同步它们的执行
    • wait() 和 notify() 的等待和通知机制
    • Semaphore 信号量机制:一种控制对有限数量的共享资源访问的机制。它可以用来限制并发访问的数量
    • CyclicBarrier 栅栏机制:一组线程可以在一个共同点(栅栏)处相互等待,直到最后一个线程到达,所有线程才会继续执行。
    • 以及 Condition 的锁机制:一种控制对有限数量的共享资源访问的机制。它可以用来限制并发访问的数量
  • 线程状态
状态描述
new创建好线程,尚未启动
runnable正在执行的
blocked阻塞等待的
waiting等待的
timed_waiting定时等待
terminated终止状态

  • 线程安全
特性描述解决方法
原子性操作不可再分,也不可被影响加锁
内存可见性一个线程对内存数据的修改必须让其它线程可知加锁,volatile
有序性指令按照原本的顺序执行volatile
  • volatile
    • 禁止编译器对变量的优化
    • 保证内存可见性
    • 禁止指令重排序
    • 写时屏障对上,读时屏障对下
  • synchronized原理,对象是如何与锁关联
    • Monitor(JVM,C++)
      • Owner,获取锁的线程
      • EntryList,处于“Blocked”的线程
      • WaitSet,处于“Waiting”的线程
    • 对象内存的对象头
      • markWord的锁指针指向Monitor对象
  • synchronized 锁升级机制也叫做锁膨胀机制
    • 无锁 → 偏向锁 → 轻量级锁 → 重量级锁
    • 锁可以升级但不能降级
解释
无锁没有线程来获取锁
偏向锁第一个来获锁的线程
轻量级锁多个线程获取锁,但彼此间竞争不重,自旋等待
重量级锁自旋超过限度,锁竞争激烈,相互互斥
  • CAS
    • Compare And Swap(比较再交换)
    • 比较x1和x2,同则将x1修改为x3
    • CPU上的一个原子性指令,操作都是原子的
    • 可以实现乐观锁
  • AQS
    • AbstractQueuedSynchronizer(抽象队列同步器)
    • 实现的锁策略
      • 可重入锁
      • 悲观锁
      • 公平锁和非公平锁
      • 共享锁和独占锁
部件描述
state状态码,0无锁,1占有,>1线程重入多次
FIFO队列先进先出队列,阻塞中的线程
  • ReentrantLock
    • 可重入锁,公平锁,不公平锁
    • CAS + AQS,继承与AQS
部件描述
state状态码,0无锁,1占有,>1线程重入多次
FIFO队列先进先出队列,阻塞中的线程
exclusiveOwnerThread当前占住锁的线程
  • synchronized和lock的区别
synchronizedlock
关键字接口
能实现的锁策略有限能提供更多类型的锁
使用简单,性能不错指定适合的锁,能提供更好的性能
  • 各种锁策略
描述
共享锁/排他锁(读写锁)读可多个线程得,写仅一个线程得
公平锁/非公平锁先到先得,无序竞争
乐观锁/悲观锁修改失败则重试,禁止其它修改
轻量级锁/重量级锁操作系统的互斥量(Mutex),前者不阻塞其它队列,后者阻塞
可重入锁同个线程可获取多次锁
偏向锁不加锁,仅标记首次获取锁的线程
自旋锁不阻塞,一直尝试获取锁
互斥锁仅一线程可获取锁,阻塞其它线程
  • 各种实现的锁
简介
ReentrantLock可重入锁
ReentrantReadWriteLock悲观读写锁
StampedLock乐观读写锁
  • 死锁
    • 多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放
    • 死锁的解决方法
      • 按顺序加锁
      • 给锁设置过期时间
    • 死锁的排查方法
      • 借助jps,jstack,jconsole,jvisualvm等工具
    • 死锁四大条件
条件解释
互斥使用资源被某线程使用后,其它线程不能使用
不可抢占请求者不能从占有者抢占资源,只能等占有者自行释放
请求和保持请求其它资源时保持对现有资源的占有
环路等待等待资源时出现了一个环路,A需要B占资源,B需要A占资源
  • ConcurrentHashMap的底层原理
    • JDK1.7,Segment分段锁,底层使用的是ReentrantLock
    • JDK1.8,CAS添加新节点,采用synchronized锁定链表或红黑二叉树的首节点,相对Segment分段锁粒度更细,性能更好
  • ConcurrentHashMap为什么不能插入Null
    • 二义性,是没有键值对?还是value为null?
    • 多线程环境下导致内存不可见
  • ThreadLocal
    • 哈希表,key是线程id,value是资源的独立副本
    • 内存泄漏
      • key 是弱引用,值为强引用
      • key 会被GC 释放内存,关联 value 的内存并不会释放
      • 主动remove删除键值对
      • 使用FastThreadLocal

  • 线程池核心参数
参数解释
corePoolSize核心线程数(N+1和2N+1)
maximumPoolSize最大线程数
keepAliveTime空闲工作线程的存活时间
unit时间单位
workQueue存储任务的阻塞队列
threadFactory线程创建工厂
handler处理方式,拒绝策略
  • 拒绝策略
拒绝策略解释
AbortPolicy直接抛出异常,默认策略
CallerRunsPolicy用调用者所在的线程来执行任务
DiscardOldestPolicy丢弃阻塞队列中靠最前的任务,并执行当前任务
DiscardPolicy直接丢弃任务
  • 线程池执行流程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 常见阻塞队列
阻塞队列解释
ArrayBlockingQueue基于数组结构的有界阻塞队列,FIFO
LinkedBlockingQueue基于链表结构的有界阻塞队列,FIFO
DelayedWorkQueue是一个优先级队列,它可以保证每次出队的任务都是当前队列中执行时间最靠前的
SynchronousQueue不存储元素的阻塞队列,每个插入操作都必须等待一个移出操作
  • LinkedBlockingQueue和ArrayBlockingQueue的区别
LinkedBlockingQueueArrayBlockingQueue
默认无界,支持有界强制有界
底层是链表底层是数组
是懒惰的,创建节点的时候添加数据提前初始化Node数组
入队会生成新 NodeNode需要是提前创建好的
两把锁(头尾)一把锁
  • 创建各种线程池
    • Executors类提供的创建线程池的方法
描述线程池创建方法
固定线程数的线程池newFixedThreadPool()
单个线程的线程池newSingleThreadExecutor()
可缓存的线程池newCachedThreadPo0l()
可延迟,可周期的线程池newScheduledThreadPool()
  • 为什么不建议用Executor创建线程池

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值