数据同步,锁的使用(二)-几种锁的概念

发表于2016-10-29
评论0 2k浏览

  锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和ReentrantLock等等 ) 。这些已经写好提供的锁为我们开发提供了便利,但是锁的具体性质以及类型却很少被提及。我们先来了解一些锁的概念。

1、阻塞锁
  阻塞锁,与自旋锁不同,阻塞锁改变了线程的运行状态。在JAVA环境中,线程Thread有如下几个状态:
        新建状态
        就绪状态
        运行状态
        阻塞状态
        死亡状态
  阻塞锁,可以说是让线程进入阻塞状态进行等待,当获得相应的信号(唤醒,时间) 时,才可以进入线程的准备就绪状态,准备就绪状态的所有线程,通过竞争,进入运行状态。
  JAVA中,能够进入退出、阻塞状态或包含阻塞锁的方法有 ,synchronized关键字(其中的重量锁),ReentrantLock,Object.wait()notify(),LockSupport.park()/unpart()(j.u.c经常使用)
  阻塞锁的优势在于,阻塞的线程不会占用cpu时间,不会导致 CPu占用率过高,但进入时间以及恢复时间都要比自旋锁略慢。在竞争激烈的情况下阻塞锁的性能要明显高于自旋锁。
  理想的情况则是; 在线程竞争不激烈的情况下,使用自旋锁,竞争激烈的情况下使用,阻塞锁。

2、可重入锁
  什么是可重入锁:可重入锁的概念是自己可以再次获取自己的内部锁。举个例子,比如一条线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获取的(如果不可重入的锁的话,此刻会造成死锁)。说的更高深一点可重入锁是一种递归无阻塞的同步机制。

3、读写锁
  什么叫读写锁:读写锁拆成读锁和写锁来理解。读锁可以共享,多个线程可以同时拥有读锁,但是写锁却只能只有一个线程拥有,而且获取写锁的时候其他线程都已经释放了读锁,而且该线程获取写锁之后,其他线程不能再获取读锁。简单的说就是写锁是排他锁,读锁是共享锁。Java中实现读写锁的类是:ReentrantReadWriteLock;

4、公平锁和非公平锁
  获取锁涉及到的两个概念即公平和非公平 :公平表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO顺序。而非公平就是一种获取锁的抢占机制,和公平相对就是先来不一定先得,这个方式可能造成某些线程饥饿(一直拿不到锁)。synchronized就是非公平锁,而ReentrantLock可以在使用的时候设置它为公平锁还        是非公平锁。ReentrantLock reentrantLock = newReentrantLock(false);  false是非公平锁,true是公平锁,默认是false;

5、互斥锁
  互斥锁是指一个锁只能被一个线程拥有,另一个线程想要获得这个锁,必须等其它线程释放这个锁。比如synchronized,ReentrantLock等都是互斥锁

6、悲观锁(Pessimistic Lock)
  顾名思义,就是很悲观,每次去操作共享数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞,直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

7、乐观锁(Optimistic Lock)
  顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,memcache的cas就使用了乐观锁。

 看了上面的文章 热爱游戏创作的你是不是已经开始热血沸腾了呢?是不是迫不及待的想加入游戏团队成为里面的一员呢?
  福利来啦~赶快加入腾讯GAD交流群,人满封群!每天分享游戏开发内部干货、教学视频、福利活动、和有相同梦想的人在一起,更有腾讯游戏专家手把手教你做游戏!
腾讯GAD游戏程序交流群:484290331

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引