并发编程(java锁)
2018-11-20 15:01:23 0 举报
AI智能生成
此图示对Java的多线程编程使用的一些知识点作了比较详细的总结,提供给一些java开发者参考和熟悉
作者其他创作
大纲/内容
并发编程(java锁)
内部锁synchronized
排他锁
synchronized特性
可见性
有序性
原子性
synchronized可以修饰方法或者代码块
synchronized修饰方法
synchronized修饰代码块
一个锁句柄(一个对象的引用或者是一个可以返回对象的表达式)
JVM 将确保锁会获得自动释放。
显式锁和解锁Lock接口
Lock接口中定义了一组抽象的加锁操作
其实现类如ReentrantLock(重入锁)
非公平锁
ReentrantLock的构造方法无参时是构造非公平锁
公平锁
线程加锁的顺序来分配的,传入一个boolean值,true时为公平锁传入一个boolean值,true时为公平锁
ReentrantLock获取锁定与三种方式
lockInterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断,或者去干别的事情
lock 必须在 finally 块中释放
ThreadLocal
ThreadLocal用于创建线程的本地变量
ThreadLocal为每个线程维护一个本地变量:采用空间换时间
它用于线程间的数据隔离,为每一个使用该变量的线程提供一个副本,每个线程都可以独立地改变自己
ThreadLocal类中维护一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值为对应线程的变量副本。
volatile
子主volatile变量可以保证下一个读取操作会在前一个写操作之后发生
任何被volatile修饰的变量,都不拷贝副本到工作内存,任何 修改都及时写在主存
对变量的写操作不依赖于当前值
该变量没有包含在具有其他变量的不变式中.
Volatile和Synchronized四个不同点
粒度不同,前者针对变量 ,后者锁对象和类
syn阻塞,volatile线程不阻塞
syn保证三大特性,volatile不保证原子性
syn编译器优化,volatile不优化
乐观锁与悲观锁
悲观锁
在做操作之前先上锁
在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题。
一个线程持有锁会导致其它所有需要此锁的线程挂起。
如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能风险
乐观锁
不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。
适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制
Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。
CAS是乐观锁技术:当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。
CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做
synchronized的优化,线程自旋和适应性自旋
java’线程其实是映射在内核之上的,线程的挂起和恢复会极大的影响开销。
很多线程在等待锁的时候,在很短的一段时间就获得了锁,所以它们在线程等待的时候,并不需要把线程挂起,而是让他无目的的循环,一般设置10次。这样就避免了线程切换的开销,极大的提升了性能
锁优化
尽量不要锁住方法
缩小同步代码块,只锁数据
锁中尽量不要再包含锁
将锁私有化,在内部管理锁
进行适当的锁分解
避免死锁的技术
加锁顺序(线程按照一定的顺序加锁)
加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)
死锁检测
ConcurrentHashMap
ConcurrentMap接口和它的一个实现类ConcurrentHashMap
比起Hashtable和synchronizedMap来,它提供了好得多的并发性
多个读操作几乎总可以并发地执行,
同时进行的读和写操作通常也能并发地执行,
而同时进行的写操作仍然可以不时地并发进行
锁的特性
排他性
阻塞性
可重入性
替代锁的同步机制解决方案
volatile关键字
final关键字
static关键字
原子变量以及各种并发容器和框架.
策略模式
保护对象:被保护的对象只能通过持有特定的锁来访问。
读写锁——(Read/WriteLock):
synchronized和ReentrantLock对比
(少量同步)资源竞争不激烈的情形下,ReentrantLock性能稍微比synchronized差点点。但是当同步非常激烈的时候
(大量同步)当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。
锁状态,synchronized无法判断,而ReentrantLock可以判断
锁的类型
synchronized 可重入 不可中断 非公平
ReentrantLock 可重入 可判断 可公平(两者皆可)
锁类型
可重入锁:在执行对象中所有同步方法不用再次获得锁
可中断锁:在等待获取锁过程中可中断
公平锁: 按等待获取锁的线程的等待时间进行获取,等待时间长的具有优先获取锁权利
读写锁:对资源读取和写入的时候拆分为2部分处理,读的时候可以多线程一起读,写的时候必须同步地写
锁的种类
偏向锁 :是一种编译解释锁。如果代码中不可能出现多线程并发争抢同一个锁的时候,JVM 编译代码,解释执行的时候,会自动的放弃同步信息。消除 synchronized 的同步代码结果。
自旋锁 :当获取锁的过程中,未获取到。为了提高效率,JVM 自动执行若干次空循环,再次申请锁,而不是进入阻塞状态的情况。称为自旋锁。自旋锁提高效率就是避免线程状态的变更
轻量级锁:过渡锁。当偏向锁不满足,也就是有多线程并发访问,锁定同一个对象的时候,先提升为轻量级锁。也是使用标记ACC_SYNCHRONIZED 标记记录的。
重量级锁 : 同步方法和同步代码块中解释的就是重量级锁
锁的使用方式为:先提供偏向锁,如果不满足的时候,升级为轻量级锁,再不满足,升级为重量级锁。自旋锁是一个过渡的锁状态,不是一种实际的锁类型
atomic包下原子操作类总结
CAS操作(又称为无锁操作)是一种乐观锁策略
无锁操作是使用CAS(compare and swap)又叫做比较交换来鉴别线程是否出现冲突,出现冲突就重试当前操作直到没有冲突为止
CAS并不是武断的间线程挂起,当CAS操作失败后会进行一定的尝试,而非进行耗时的挂起唤醒的操作,因此也叫做非阻塞同步
原子更新操作
原子更新基本类型
AtomicBoolean:以原子更新的方式更新boolean
AtomicInteger:以原子更新的方式更新Integer
AtomicLong:以原子更新的方式更新Long
原子更新数组类型
AtomicIntegerArray:原子更新整型数组中的元素
AtomicLongArray:原子更新长整型数组中的元素
AtomicReferenceArray:原子更新引用类型数组中的元素
原子更新引用类型
AtomicReference:原子更新引用类型
AtomicReferenceFieldUpdater:原子更新引用类型里的字段
AtomicMarkableReference:原子更新带有标记位的引用类型
原子更新字段类型
AtomicIntegeFieldUpdater:原子更新整型字段类
AtomicLongFieldUpdater:原子更新长整型字段类
AtomicStampedReference:原子更新引用类型,这种更新方式会带有版本号。而为什么在更新的时候会带有版本号,是为了解决CAS的ABA问题;
收藏
收藏
0 条评论
回复 删除
下一页