6、java多线程
2019-07-24 17:32:18 4 举报
AI智能生成
基于jdk1.8 Java多线程和锁梳理
作者其他创作
大纲/内容
java多线程
基础篇
线程的概念
进程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
线程
线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位,线程可以拥有自己的堆栈,自己的程序计数器和自己的局部变量,但不能拥有系统资源。它与父进程的其他线程共享该进程的所有资源。
线程分类
守护线程
设置守护线程setDaemon(boolean on)
用户线程
线程优先级
设置优先级setProority(int newProority)
线程状态和操作
创建线程
继承Thread类,重写run方法
实现Runnable接口
实现Callable接口,重写call方法
几种创建方式的优缺点
线程的状态
NEW
初始状态
RUNNABLE
运行状态
BLOCKED
阻塞状态
WAITING
等待状态
TIME_WAITING
超时状态
TERMINATED
终止状态
线程的操作
interrupt
Thread对象方法,中断interrupt() /判断是否被中断isInterrupted
join
Thread对象方法,等待线程t 结束 t.join()方法
sleep
yield
wait
notify/notifyAll
Object方法:唤醒线程notify()/notifyAll()
线程间通信
基于共享内存的通信
基于线程调度的通信
wait/notify/notifyAll
显式锁Lock的Condition
内存模型
JVM内存模型
JMM内存模型
共享主内存
堆
方法区
抽象结构
线程将数据拷贝到工作内存,再刷新到主存。 各个线程通过主存中的数据来完成隐式通信
重排序
happens-before规则
高级篇
线程同步
并发关键字
三大性质
原子性
操作的原子性
可见性
内存可见性
有序性
防止指令重排序,有序性
synchronized
如何使用?
实例方法(锁的是实例对象)
静态方法(锁的是类对象)
代码块根据配置,锁的是实例对象也可以是类对象
moniter机制
字节码中会添加monitorenter和monitorexit指令
锁的重入性:同一个锁程,不需要再次申请获取锁
synchronized的内存语义
共享变量会刷新到主存中,线程每次会从主存中 读取最新的值到自身的工作内存中
锁优化
锁状态
无锁状态
偏向锁
轻量级锁
重量级锁
JAVA对象头
对象的hashcode
对象的分代年龄
是否是偏向锁的标志位
锁标志位
锁升级策略
volatile
实现原理
内存语义
volatile特性
内存语义实现
final
禁止重排序
Lock体系
CAS
Unsafe
提供native方法
缺陷
ABA问题,解决方案
因为CAS需要在操作值的时候,检查值有没有发生变化,如果没有发生变化则更新,但是如果一个值 原来是A,变成了B,又变成了B,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。
只能保证一个共享变量的原子操作
循环时间长 开销大
AQS
AbstractQueuedSynchronizer同步器
如何使用AQS实现自定义同步组件
以下3个方法来 修改同步 状态
getState():获取当前同步状态
setState(int newState):设置当前同步状态
同步器可重写的方法基本 为3类
独占锁
共享锁
查询同步队列中的等待线程情况
Lock接口
Lock与synchronized的比较
ReentrantLock
重入锁的实现原理
公平锁
非公平锁
ReentrantReadWriteLock
适用于读多写少的应用场景,比如缓存设计上
WriteLock的获取和释放
ReadLock的获取和释放
锁降级策略
Condition机制
与Object的wait/notify机制相比 具有的特性
与Object的wait/notify相对应的方法
底层数据结构
awiat实现原理
signal/signalAll实现原理
LockSupport
可阻塞线程以及唤醒线程,功能实现依赖于Unsafe类
LockSupport通过LockSupport.unpark(thread)可以指定 哪个线程被唤醒,而synchronized不能
ThreadLocal
实现思想
采用“空间换时间的”思想,每个线程拥有变量副本,达到 隔离线程的目的,线程间不受影响解决线程安全的问题
set方法原理
数据存放在由当前线程Thread维护的ThreadLocalMap中,数据结构为 当前ThreadLocal实例为key,值为value的键值对
get方法原理
以当前ThreadLocal为键,从当前线程Thread维护的ThreadLocalMap中获取value
remove方法原理
从当前线程Thread维护的ThreadLocalMap中删除以当前ThreadLocal实例为键的键值对
ThreadLocal的最佳实践
使用完ThreadLocal后要remove掉
应用场景
hibernate管理seesion,每个线程维护其自身的session,彼此不干扰
用于解决对象不能被多个线程共享的问题
原子类
借住与Unsafe类的CAS操作,达到并发安全的目的
基本类型
AtomicInteger
AtomicLong
AtomicBoolean
数组类型
AtomicIntegerArray
AtomicLongArray
AtomicReferenceArray
引用类型
AtomicReference
AtomicStampedReference
解决ABA问题
AtomicMarkableReference
字段类型
AtomicIntegerFieldUpdater
AtomicLongFieldUpdater
AtomicReferenceFieldUpdater
并发工具类
循环栅栏CyclicBarrier
CountDownLatch
CountDownLatch和CyclicBarrier的比较
资源访问控制Semaphore
并发容器
ConcurrentHashMap
数据结构
锁的粒度
JDK1.8为什么使用内置锁synchronized来代替重入锁ReentrantLock
put()
get()
ConcurrentLinkedQueue
BlockingQueue
ArrayBlockingQueue
LinkedBlockingQueue
PriorityBlockingQueue
SynchronousQueue
LinkedTransferQueue
LinkedBlockingDeque
DelayQueue
缓存系统的设计
定时任务调度
CopyOnWrite
COW和ReentrantReadWriteLock的区别
COW的缺点
线程池
线程池的优点
降低资源消耗:通过重复利用已经创建的线程降低线程创建和销毁造成的损耗
提高效应速度:任务不需要等到线程创建就能立即执行
提高线程的可管理性:线程池统一分配,调优和监控
工作流程
核心线程是否已满,如果不是,创建一个工作线程来执行任务
工作队列是否已满,如果不是,则将任务存储在工作队列
判断所有线程是否都处于工作状态,如果不是,则创建新的工作线程,如果是,这交给饱和策略
ThreadPoolExecutor的重要参数
1.corePoolSize:核心线程数(线程池的基本大小)
2.maximumPoolSize:线程池最大数量
3.long keepAliveTime:线程活动保持时间
4.TimeUnit unit:线程保持存活时间的单位
5.BlockingQueue<Runnable> workQueue:任务队列
ArraBlockingQueue:基于数组结构的有界阻塞队列;按照FIFO先进先出的原则对元素进行排序
LinkedBlockingQueue:基于链表结构的无界阻塞队列;按照FIFO先进先出的原则对元素进行排序
SynchronousQueue:一个不存储元素的有界阻塞队列;每个插入操作必须等待另一个线程的一处操作,否则插入操作会一直阻塞
PriorityBlockingQueue:一个具有优先级的无限阻塞队列
6.ThreadFactory threadFactory:用于设置线程工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字
7.RejectedExecutionHandler handler:饱和策略
AbortPolicy:直接抛出异常
CallerRunsPolicy:只用调用者所在线程来运行任务
DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务
DiscardPolicy:不处理,直接丢弃
线程池的其他操作
提交任务
execute:提交不需要返回值的任务
submit:提交需要返回值的任务
关闭
void shutdown():将线程池的状态设置为SHUTDOWN状态,然后中断所有没有正在执行任务的线程
List<Runnable> shutdownNow():将线程池的状态设置为STOP,然后尝试停止所有正在执行或者暂停任务的线程,并返回等待执行任务的列表
isTerminated来检查线程池是否已经关闭
合理配置
cpu密集型 尽可能少的线程,比如cpu核心数+1
io密集型 尽可能多的线程,比如cpu核心数*2
任务按照IO密集型和CPU密集型进行拆分
监控
Executor体系
ThreadPoolExecutor
ExecutorService newFixedThreadPool(int nThreads):创建一个固定线程数量的线程池
ExecutorService newSingleThreadExecutor():创建使用单个线程的线程池
ExecutorService newCachedThreadPool():创建一个会根据需要创建新线程的CacheThreadPool
ScheduledThreadPoolExecutor
可 延时执行任务:schedule(.....)
可周期执行任务:scheduledAtFixedRate(...)和scheduledWithFixedDelay
SingleThreadScheduledExecutor
ExecutorService
提交任务:submit()
拒绝新任务,等待任务全部结束关闭线程池shutdown()
尝试立刻关闭线程池并返回等待执行的任务列表List<Runnable> shutdownNow()
FutureTask
实践篇
spring boot线程池使用
添加线程池配置类
service服务异步执行
监控线程池信息
hystrix实现线程池隔离
优点
如果一个任务的线程池资源耗尽,也不会影响另外一个任务的线程池。
通常的做法是按照业务进行划分
用户服务线程池
订单服务线程池
商品服务线程池
缺点
线程池的主要缺点就是它增加了计算的开销,每个业务请求(被包装成命令)在执行的时候,会涉及到请求排队,调度和上下文切换。不过Netflix公司内部认为线程隔离开销足够小,不会产生重大的成本或性能的影响。
logback异步日志
logback-spring.xml
原理
生产者-消费者问题
使用Object的wait/notifyAll方式实现
使用Object的消息通知机制可能存在的问题
标准范式
使用lock的condition的await/signalAll方式实现
使用blockingQueue方式实现
由于BlockingQueue有可阻塞的插入和删除数据的put和take方法,因此,在实现上 比使用Object和lock的方式更加简洁
收藏
收藏
0 条评论
回复 删除
下一页