volatile是变量修饰符 修改变量JMM会把该线程对应的本地内存中的变量强制刷新到主内存中去,保证变量对所有线程的可见,但不能保证原子性也不会被编译器优化 防止指令重排
synchronized互斥锁 是可重入锁 可以避免单线程内重复加锁死锁情况 S包裹代码加默认非公平锁 出异常自动释放锁 无法响应中断 S锁在JVM里的实现基于进入和退出Monitor监视器对象来实现方法同步和代码块同步
JUC.Lock可重入锁 lock.lock()/unlock()随时加锁解锁 出异常需手动释放锁,tryLock()可以尝试申请锁很公平,lockInterruptibly()被阻塞的线程可以终止等待。依赖AQS 代码可扩展
S锁修饰代码块锁定的是传入的对象,普通方法(非静态方法)时,锁的是方法的调用者 静态方法锁定的是类,不是对象,所以不管多少个对象锁的都是一个类
lock 锁住的是mLock.lock()和mLock.unlock()之间的代码块 Lock在硬件层面依赖特殊CPU指令
S的栈上锁阶段:主要是在栈上做CAS,利用对象头和LockRecord(锁记录)来判断竞争锁的情况。该阶段又可以分为多个状态,如两种起始态:“无锁状态” 和 “匿名偏向状态”,进阶状态:“”偏向状态“ 和 “轻量锁状态”
S的重量级锁阶段:基于objectMonitor对象的对象锁,只有该阶段才会出现线程的阻塞,才会出现阻塞与等待队列。我们在Object类里看到的wait() notify() 方法,其实是objectMonitor对象的方法。所以当你使用了wait() 或 notify() 后,必定会创建并进入重量级锁,这也是为什么这两个方法必须要放在synchronized代码块里的原因
Lock()方法:直接去获取锁。失败了进入阻塞等待 是可重入锁且不会死锁 但要手动释放锁。
tryLock()方法尝试获取锁 只有资源没被持有才可以取到,成功获取到锁资源之后,会立即返回true;失败即返回false 线程不用阻塞等待 加上timeout参数等待超时后返回false
独享锁是排它锁 只允许一个线程读和写
共享锁允许所有线程读 不能写
ReentrantReadWriteLock读锁是共享锁,写锁是独享锁,AQS中的state(int类32位在独享锁中这个值0或1 重入锁是重入的次数 在共享锁中state就是持有锁的数量。但在ReentrantReadWriteLock中state高16位表示读锁个数,低16位表示写锁个数
公平锁:多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一位才能得到锁。
非公平锁:多个线程去获取锁的时候,会直接去尝试获取,获取不到,再去进入等待队列排队
自旋锁默认的自旋次数为10次,用户可以使用参数-XX:PreBlockSpin来更改
自适应自旋锁JDK1.6引入自旋的时间不再固定而是由上一次这个锁上的自旋成功时间判断
偏向锁:在锁对象的对象头中记录当前获取到该锁的线程ID,线程下次来就直接获取。只有一个线程操作锁的时候,一旦有竞争就会升级到轻量锁
轻量级锁:第⼆个线程来竞争偏向锁就会升级为轻量级锁,底层是通过⾃旋实现,不会阻塞线程,用CAS机制来竞争锁
重量级锁: 如果⾃旋次数过多仍然没有获取到锁或者有第三个来访时会升级为重量级锁会导致线程阻塞
死锁
1.互斥条件:共享资源x和y只能被一个线程占用
2.占有且等待:线程t1已经取得共享资源x在等待共享资源x在等待共享资源y的时候,不释放共享资源x
3.不可抢占:其他线程不能强行抢占线程t1占有的资源
4.循环等待:线程t1等待线程t2占有的资源,线程t2等待线程t1占有的资源
解决:1可一次性申请所有的资源。2占有部分资源的线程如果申请不到其他资源可以主动释放它占有的资源。3按顺序申请,资源是有线性顺序的。4tryLock可以设置超时时间。5只锁需要的部分
============================================================
@Synchronized和s锁一样锁方法参数 注解锁默认生成$lock的常量 可以指定锁的成员变量value=“name”