Java锁机制

synchronized关键字

synchronized是一种同步锁。它修饰的对象有以下几种:

  • 一个代码块,被修饰的代码块称为同步语句块,作用的对象是调用这个代码块的对象;
  • 一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
  • 一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
  • 一个类,其作用的范围是synchronized后面括号括起来的部分,作用的对象是这个类的所有对象。
    http://blog.csdn.net/luoweifu/article/details/46613015
    修饰一个代码块:
    1)当两个并发线程(thread1和thread2)访问同一个对象(syncThread)中的synchronized代码块时,在同一时刻只能有一个线程得到执行,另一个线程受阻塞,必须等待当前线程执行完这个代码块以后才能执行该代码块。Thread1和thread2是互斥的,因为在执行synchronized代码块时会锁定当前的对象,只有执行完该代码块才能释放该对象锁,下一个线程才能执行并锁定该对象。
    2)因为synchronized只锁定对象,每个对象只有一个锁与之相关联,创建了两个SyncThread的对象syncThread1和syncThread2,线程thread1执行的是syncThread1对象中的synchronized代码,而线程thread2执行的是syncThread2对象中的synchronized代码;因为synchronized锁定的是对象,这时会有两把锁分别锁定syncThread1对象和syncThread2对象,而这两把锁是互不干扰的,不形成互斥,所以两个线程可以同时执行。
    3)当一个线程访问对象的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该对象中的非synchronized(this)同步代码块。
    修饰一个静态的方法:
    静态方法是属于类的而不属于对象的。同样的,synchronized修饰的静态方法锁定的是这个类的所有对象。

volatile

volatile 不能保证原子性
volatile是java虚拟机提供的最轻量级的同步机制。volatile所修饰的变量是直接存在于主内存中的,线程对变量的操作也是直接反映在主内存中。

  • 第一,保证变量对所有线程的可见性,即当一条线程改变了这个变量的值,新值对于其他所有线程是立即得知的。(而普通变量的值在线程间传递均需要通过主内存来完成);
  • 第二,禁止指令重排序优化。

lock

lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中。

独占锁

独占锁是一种悲观锁,synchronized就是一种独占锁,会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁。而另一个更加有效的锁就是乐观锁。乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。
乐观锁用到的机制就是CAS。

CAS

CAS来实现原子操作(Compare and Swap):
CAS 操作包含三个操作数:
内存位置(V)、预期原值(A)和新值(B)
如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值 。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值。(在 CAS 的一些特殊情况下将仅返回 CAS 是否成功,而不提取当前值。)CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。

ReenTrantLock

ReenTrantLock独有的能力:(是java.util.concurrent包下提供的一套互斥锁)

  • ReenTrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。
  • ReenTrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。
  • ReenTrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。
  • ReenTrantLock的实现是一种自旋锁,通过循环调用CAS操作来实现加锁。它的性能比较好也是因为避免了使线程进入内核态的阻塞状态。
    ReentrantLock底层实现机制(讲源码) http://www.blogjava.net/zhanglongsr/articles/356782.html

ReentrantLock的实现基于AQS(AbstractQueuedSynchronizer)和LockSupport。
AQS主要利用硬件原语指令(CAS compare-and-swap),来实现轻量级多线程同步机制,并且不会引起CPU上文切换和调度,同时提供内存可见性和原子化更新保证(线程安全的三要素:原子性、可见性、顺序性)。
AQS的本质上是一个同步器/阻塞锁的基础框架,其作用主要是提供加锁、释放锁,并在内部维护一个FIFO等待队列,用于存储由于锁竞争而阻塞的线程。AQS使用链表作为队列,使用volatile变量state,作为锁状态标识位。
从ReentrantLock的构造子可以看到,ReentrantLock提供两种锁:公平锁和非公平锁,其内部实现了两种同步器NonfairSync、FairSync派生自AQS,主要才采用了模板方法模式,主要重写了AQS的tryAcquire、lock方法

synchronied和ReentrantLock的区别

  • 这两种同步方式最大区别就是对于Synchronized来说,它是java语言的关键字,是原生语法层面的互斥,需要jvm实现。
  • 而ReentrantLock是API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成。
  • Synchronized关键字经过编译,会在同步块的前后分别形成monitorenter和monitorexit这个两个字节码指令。在执行monitorenter指令时,首先要尝试获取对象锁。如果这个对象没被锁定,或者当前线程已经拥有了那个对象锁,把锁的计算器加1,相应的,在执行monitorexit指令时会将锁计算器就减1,当计算器为0时,锁就被释放了。如果获取对象锁失败,那当前线程就要阻塞,直到对象锁被另一个线程释放为止。
  • Synchronized同步块对同一条线程来说是可重入的。

jdk1.6发布后JVM对synchronied做出相应的优化

  • 锁消除:当JVM判定该资源不会被其他线程争夺的时候就会消除该锁;
  • 自旋锁:让后面请求锁的线程忙循环,不放弃处理器的执行时间,虽然避免了线程切换的开销,但是占用处理器时间;
  • 自适应自旋锁:自旋的时间不再固定,由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。
  • 锁粗化
  • 轻量级锁
  • 偏向锁。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值