Lock 与 Synchronized

5 篇文章 0 订阅
4 篇文章 0 订阅

多线程保证数据的线程安全与数据同步

  多线程开发中不可避免的要用到锁,一段被加锁的代码被一个线程执行之前,线程要先拿到执行这段代码的权限,在Java里边就是拿到某个同步对象的锁(一个对象只有一把锁),如果这个时候同步对象的锁被其他线程拿走了,这个线程就只能等了(线程阻塞在锁池等待队列中)。拿到权限(锁)后,他就开始执行同步代码,线程执行完同步代码后马上就把锁还给同步对象,其他在锁池中等待的某个线程就可以拿到锁执行同步代码了。这样就保证了同步代码在统一时刻只有一个线程在执行。Java中常用的锁有synchronized和Lock两种。
  锁的特点:每个对象只有一把锁,不管是synchronized还是Lock它们锁定的只能是某个具体对象,也就是说该对象必须是唯一的,才能被锁起,不被多个线程同时使用。

synchronized的特点

J.DK1.4前是通过synchronized实现。同步锁,当它锁定的方法或者代码块发生异常的时候,它会在自动释放锁;但是如果被它锁定的资源被线程竞争激烈的时候,它的表现就没那么好了。

Lock

JDK1.5后加入java.util.concurrent.locks包下的各种lock。由于我们提到synchronized无法中断一个正在等候获得锁的线程,也无法通过投票得到锁,如果不想等下去,也就没法得到锁。所以JSR 166小组花时间为我们开发了java.util.concurrent.lock框架,当Lock锁定的方法或者代码块发生异常的时候,它不会自动释放锁;它拥有与synchronized相同的并发性和内存语义,但是添加了类似锁投票、定时锁等候和可中断锁等候的一些特性。此外,它还提供了在激烈争用情况下更佳的性能。(换句话说,当许多线程都想访问共享资源时,JVM 可以花更少的时候来调度线程,把更多时间用在执行线程上。)

代码层的区别

synchronized:在代码里,synchronized类似“面向对象”,修饰类、方法、对象。      Lock:不作为修饰,类似“面向过程”,在方法中需要锁的时候lock,在结束的时候unlock(一般都在finally块里)。  例如代码:   
Java代码   
 public void method1() {   
    synchronized(this){//旧锁,无需人工释放   

   System.out.println(1);     }   

}        
 public void method2() {   
     Lock lock = new ReentrantLock();   //一个重入锁ReenTrantLock(为Lock的实现类)

     lock.lock();//上锁   

     try{   
         System.out.println(2);   

     }finally{   

        lock.unlock();//解锁   

      }    

性能:在并发高是,lock性能优势很明显,在低并发时,synchronized也能取得优势


LOCK和synchronized的实现机制: 
下面继续讨论怎么由代码层到native的过程。  
1 synchronized -- 对象加锁 

所有对象都自动含有单一的锁,JVM负责跟踪对象被加锁的次数。如果一个对象被解锁,其计数变为0。在任务(线程)第一次给对象加锁的时候, 计数变为1。每当这个相同的任务(线程)在此对象上获得锁时,计数会递增。 只有首先获得锁的任务(线程)才能继续获取该对象上的多个锁。每当任务离开时,计数递减,当计数为0的时候,锁被完全释放。synchronized就是基于这个原理,同时synchronized靠某个对象的单一锁技术的次数来判断是否被锁,所以无需(也不能)人工干预锁的获取和释放。

synchronized原理

synchronized原理是基于栈中的某对象来控制一个框架,所以对于synchronized有常用的优化是锁对象不锁方法。实际上 synchronized作用于方法时,锁住的是“this”,作用于静态方法/属性时,锁住的是存在于永久带的CLASS,相当于这个CLASS的全局 锁,锁作用于一般对象时,锁住的是对应代码块。在HotSpot中JVM实现中,锁有个专门的名字:对象监视器。    
当多个线程同时请求某个对象监视器时,对象监视器会设置几种状态用来区分请求的线程 Contention List:所有请求锁的线程将被首先放置到该竞争队列,是个虚拟队列,不是实际的Queue的数据结构。  
Entry List:EntryList与ContentionList逻辑上同属等待队列,ContentionList会被线程并发访问,为了降低对 ContentionList队尾的争用,而建立EntryList。

Contention List中那些有资格成为候选人的线程被移到Entry List 。Wait Set:那些调用wait方法被阻塞的线程被放置到Wait Set 。
OnDeck:任何时刻最多只能有一个线程正在竞争锁,该线程称为OnDeck 。Owner:获得锁的线程称为Owner  !Owner:释放锁的线程  。

lock原理

 LOCK -- 基于栈中的框架而不是对象级别

Lock不同于synchronized面向对象,它基于栈中的框架而不是某个具体对象,所以Lock只需要在栈里设置锁的开始和结束 (lock和unlock)的地方就行了(人工必须标明)。

,不用关心框架大小对象的变化等等。这么做的好处是Lock能提供无条件的、可轮询的、定时的、 可中断的锁获取操作。


综合来看对于所有的高并发情况,采用Lock加锁是最优选择,但是由于历史遗留等问题,synchronized也还是不能完全被淘汰,同时,在低并发情况下,synchronized的性能还是比Lock好的。

待完善。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值