精华内容
下载资源
问答
  • 以下是对Sql server锁,独占锁,共享锁,更新锁,乐观锁,悲观锁进行了详细的介绍,需要的朋友可以过来参考下
  • 独占锁与共享锁

    千次阅读 2019-08-09 19:38:11
    独占锁与共享锁前言概念引入独占锁概念共享锁概念源码分析ReentrantReadWriteLock源码读锁和写锁的具体加锁方式有什么区别 前言 独占锁和共享锁同样是一种概念。我们先介绍一下具体的概念,然后通过ReentrantLock和...

    前言

    独占锁和共享锁同样是一种概念。我们先介绍一下具体的概念,然后通过 ReentrantLock 和 ReentrantReadWriteLock 的源码来介绍独占锁和共享锁。

    概念引入

    独占锁概念

    独占锁也叫排他锁,是指该锁一次只能被一个线程所持有。如果线程T对数据A加上排他锁后,则其他线程不能再对A加任何类型的锁。获得排它锁的线程即能读数据又能修改数据。JDK中的synchronized和 JUC中Lock的实现类就是互斥锁。

    共享锁概念

    共享锁是指该锁可被多个线程所持有。如果线程T对数据A加上共享锁后,则其他线程只能对A再加共享锁,不能加排它锁。获得共享锁的线程只能读数据,不能修改数据。 独享锁与共享锁也是通过AQS来实现的,通过实现不同的方法,来实现独享或者共享。

    源码分析

    ReentrantReadWriteLock源码

    在这里插入图片描述
    我们看到 ReentrantReadWriteLock 有两把锁:ReadLock和WriteLock,见名知意,一个读锁一个写锁, 合称“读写锁”。
    再进一步观察可以发现 ReadLock 和 WriteLock 是靠内部类 Sync 实现的锁。
    Sync 是 AQS 的一个子类,这种结构在 CountDownLatch 、ReentrantLock 、Semaphore 里面也都存在。
    在ReentrantReadWriteLock 里面,读锁和写锁的锁主体都是 Sync ,但读锁和写锁的加锁方式不一样。
    读锁是共享锁,写锁是独占锁。读锁的共享锁可保证并发读非常高效,而读写、写读、写写的过程互斥,因为读锁和写锁是分离的。所以ReentrantReadWriteLock的并发性相比一般的互斥锁有了很大提升。

    读锁和写锁的具体加锁方式有什么区别

    在了解源码之前我们需要回顾一下其他知识。 在最开始提及 AQS 的时候我们也提到了state字段(int类型,32位),该字段用来描述有多少线程获持有锁。 在独享锁中这个值通常是0或者1(如果是重入锁的话state值就是重入的次数),在共享锁中state就是持有锁的数量。但是在 ReentrantReadWriteLock 中有读、写两把锁,所以需要在一个整型变量state上分别描述读锁和写锁的数量(或者也可以叫状态)。于是将state变量“按位切割”切分成了两个部分,高16位 表示读锁状态(读锁个数),低16位表示写锁状态(写锁个数)。如下图所示:
    在这里插入图片描述

    protected final boolean tryAcquire(int acquires) {
    	Thread current = Thread.currentThread();
    	int c = getState(); // 取到当前锁的个数
    	int w = exclusiveCount(c); // 取写锁的个数w
    	if (c != 0) { // 如果已经有线程持有了锁(c!=0)
    		// (Note: if c != 0 and w == 0 then shared count != 0)
    		if (w == 0 || current != getExclusiveOwnerThread()) // 如果写线程数(w)为0(换言之存在读锁) 或者持有锁的线程	不是当前线 程就返回失败
    				return false;
    		if (w + exclusiveCount(acquires) > MAX_COUNT) // 如果写入锁的数量大于最大数(65535,2的16次方-1)就抛出一个Error。
    		throw new Error("Maximum lock count exceeded");
    // Reentrant acquire
    		 setState(c + acquires);
    		return true;
     }
    if (writerShouldBlock() || !compareAndSetState(c, c + acquires)) // 如果当且写线程数为0,并且当前线程需要阻塞那么就返回失败;或者如果通过CAS增加写线程数失败也返回失败。
    		return false;
    	setExclusiveOwnerThread(current); // 如果c=0,w=0或者c>0,w>0(重入),则设置当前线程或锁的拥有者
    	return true; 
    }
    
    • 这段代码首先取到当前锁的个数c,然后再通过c来获取写锁的个数w。因为写锁是低16位,所以取低16位的最大值与当前的c做与运算( int w = exclusiveCount©; ),高16位和0与运算后是0,剩下的就是低位运算的值,同时也是持 有写锁的线程数目。
    • 在取到写锁线程的数目后,首先判断是否已经有线程持有了锁。如果已经有线程持有了锁(c!=0),则查看当前写锁线程的数目,如果写线程数为0(即此时存在读锁)或者持有锁的线程不是当前线程就返回失败。
    • 如果写入锁的数量大于最大数(65535,2的16次方-1)就抛出一个Error。
    • 如果当且写线程数为0(那么读线程也应该为0,因为上面已经处理c!=0的情况),并且当前线程需要阻塞那么就返 回失败;如果通过CAS增加写线程数失败也返回失败。
    • 如果c=0,w=0或者c>0,w>0(重入),则设置当前线程或锁的拥有者,返回成功!

    tryAcquire()除了重入条件(当前线程为获取了写锁的线程)之外,增加了一个读锁是否存在的判断。
    如果存在读锁,则写锁不能被获取,原因在于:
    必须确保写锁的操作对读锁可见,如果允许读锁在已被获取 的情况下对写锁的获取,那么正在运行的其他读线程就无法感知到当前写线程的操作。
    因此,只有等待其他读线程都释放了读锁,写锁才能被当前线程获取,而写锁一旦被获取,则其他读写线程的后续访问均被阻塞。写锁的释放与 ReentrantLock 的释放过程基本类似,每次释放均减少写状态,当写状态为0时表示写锁已被释放,然后等待的读写线程才能够继续访问读写锁,同时前次写线程的修改对 后续的读写线程可见。 接着是读锁的代码:

    protected final int tryAcquireShared(int unused) {
     	Thread current = Thread.currentThread();
    	int c = getState();
    	if (exclusiveCount(c) != 0 &&getExclusiveOwnerThread() != current)
    		return -1; // 如果其他线程已经获取了写锁,则当前线程获取读锁失败,进入等待状态
    	int r = sharedCount(c);
    	if (!readerShouldBlock() &&r < MAX_COUNT &&compareAndSetState(c, c + SHARED_UNIT)) {
    		if (r == 0) {
     			firstReader = current;
     			firstReaderHoldCount = 1;
     		} else if (firstReader == current) {
     			firstReaderHoldCount++;
     		} else {
     			HoldCounter rh = cachedHoldCounter;
    			if (rh == null || rh.tid != getThreadId(current))
     				cachedHoldCounter = rh = readHolds.get();
    			else if (rh.count == 0)
     				readHolds.set(rh);
     				rh.count++;
     		}
    		return 1;
     	}
    	return fullTryAcquireShared(current);
    }
    

    可以看到在 tryAcquireShared(int unused) 方法中,如果其他线程已经获取了写锁,则当前线程获取读锁 失败,进入等待状态。如果当前线程获取了写锁或者写锁未被获取,则当前线程(线程安全,依靠CAS保证)增加读状态,成功获取读锁。读锁的每次释放(线程安全的,可能有多个读线程同时释放读锁)均减少读状态,减少的值是“1<<16”。所以读写锁才能实现读读的过程共享,而读写、写读、写写的过程互斥。

    展开全文
  • 解决VC++ 在多线程开发时,在对数据的操作中,操作次数太多,造成的速度下降的问题。本程序主要帮助实现对数据读写权限的管控,实现多线程时数据的安全性和数据隔离
  • java并发包提供的加锁模式分为独占锁和共享锁,独占锁模式下,每次只能有一个线程能持有锁,ReentrantLock就是以独占方式实现的互斥锁。共享锁,则允许多个线程同时获取锁,并发访问 共享资源,如:ReadWriteLock。...

    引言

    本文继续讲解 Java 并发编程实践的基础篇,今天来说说并发编程中锁的概念。不同领域,对锁的分类也不同,比如数据库的表锁、行锁等,它们因底层细节的差异,而有了各自的名字。扩展到整个 IT 技术领域,衍生出的那些名目繁多的锁,大抵也都是这样产生的。

    Java 语言中,最顶层锁的实现方式,只有内置锁和显式锁两种。但是,这两种锁在实现过程中,遭遇到了各种处理方式的选择,不同的处理方式,也对应着一种锁,比如:

    1. 已经被某个线程持有的锁,是否允许其他线程线程同时持有呢?【独占/共享】
    2. 多个线程阻塞在同一个条件队列上时,先唤醒谁呢?已经有线程排队等待某个锁时,又有新的线程请求该锁,而恰好该锁被释放了,是否允许新线程插队获取锁呢?【公平/非公平】
    3. 已经持有锁的线程,还想继
    展开全文
  • 共享锁和独占锁 独占锁独占锁也叫排他锁,是指该锁一次只能被一个线程所持有。如果线程对数据A加上排他锁后,则其他线程不能再对A加任何类型的锁。获得排它锁的线程即能读数据又能修改数据。 共享锁:共享锁是指该...

    共享锁和独占锁
    独占锁:独占锁也叫排他锁,是指该锁一次只能被一个线程所持有。如果线程对数据A加上排他锁后,则其他线程不能再对A加任何类型的锁。获得排它锁的线程即能读数据又能修改数据。
    共享锁:共享锁是指该锁可被多个线程所持有。如果线程对数据A加上共享锁后,则其他线程只能对A再加共享锁,不能加排它锁。获得共享锁的线程只能读数据,不能修改数据。

    展开全文
  • java并发-独占锁与共享锁

    千次阅读 2019-06-28 09:21:11
    java并发包提供的加锁模式分为独占锁和共享锁,独占锁模式下,每次只能有一个线程能持有锁,ReentrantLock就是以独占方式实现的互斥锁。共享锁,则允许多个线程同时获取锁,并发访问 共享...

    转自:https://blog.csdn.net/wojiushiwo945you/article/details/42292999

    另外可以看下这个:https://blog.csdn.net/luofenghan/article/details/75065001

    1 锁的独占与共享

          java并发包提供的加锁模式分为独占锁和共享锁,独占锁模式下,每次只能有一个线程能持有锁,ReentrantLock就是以独占方式实现的互斥锁。共享锁,则允许多个线程同时获取锁,并发访问 共享资源,如:ReadWriteLock。AQS的内部类Node定义了两个常量SHARED和EXCLUSIVE,他们分别标识 AQS队列中等待线程的锁获取模式。

         很显然,独占锁是一种悲观保守的加锁策略,它避免了读/读冲突,如果某个只读线程获取锁,则其他读线程都只能等待,这种情况下就限制了不必要的并发性,因为读操作并不会影响数据的一致性。共享锁则是一种乐观锁,它放宽了加锁策略,允许多个执行读操作的线程同时访问共享资源。 java的并发包中提供了ReadWriteLock,读-写锁。它允许一个资源可以被多个读操作访问,或者被一个 写操作访问,但两者不能同时进行。

    2 锁的公平与非公平

         锁的公平与非公平,是指线程请求获取锁的过程中,是否允许插队。在公平锁上,线程将按他们发出请求的顺序来获得锁;而非公平锁则允许在线程发出请求后立即尝试获取锁,如果可用则可直接获取锁,尝试失败才进行排队等待。ReentrantLock提供了两种锁获取方式,FairSyn和NofairSync。结论:ReentrantLock是以独占锁的加锁策略实现的互斥锁,同时它提供了公平和非公平两种锁获取方式。最初看源码时竟然把这两个概念弄混了。

     3 AQS提供的模板方法

        AQS提供了独占锁和共享锁必须实现的方法,具有独占锁功能的子类,它必须实现tryAcquire、tryRelease、isHeldExclusively等;共享锁功能的子类,必须实现tryAcquireShared和tryReleaseShared等方法,带有Shared后缀的方法都是支持共享锁加锁的语义。Semaphore是一种共享锁,ReentrantLock是一种独占锁。

        独占锁获取锁时,设置节点模式为Node.EXCLUSIVE

    public final void acquire(int arg) {
            if (!tryAcquire(arg) &&
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                selfInterrupt();
        }
    
         private void doAcquireShared(int arg) {
            final Node node = addWaiter(Node.SHARED);
            boolean failed = true;
            .....
        }
    

     4  对ConditionObject的认识

         ReentrantLock是独占锁,而且AQS的ConditionObject只能与ReentrantLock一起使用,它是为了支持条件队列的锁更方便。ConditionObject的signal和await方法都是基于独占锁的,如果线程非锁的独占线程,则会抛出IllegalMonitorStateException。例如signalAll源码:

            public final void signalAll() {
                if (!isHeldExclusively())
                    throw new IllegalMonitorStateException();
                Node first = firstWaiter;
                if (first != null)
                    doSignalAll(first);
            }
    

          我在想,既然Condtion是为了支持Lock的,为什么ConditionObject不作为ReentrantLock的内部类呢?对于实现锁功能的子类,直接扩展它就可以实现对条件队列的支持。但是,对于其它非锁语义的实现类如Semaphore、CountDownLatch等类来说,条件队列是无用的,也会给开发者扩展AQS带来困惑。总之,是各有利弊,大师们的思想,还需要仔细揣摩啊!

    展开全文
  • 将这两个锁之前,我先讲下上一章遗留的...共享锁和独占锁 共享锁,顾名思义,就是这个锁是共享的,咱们能一起使用这个锁。这个就像进男厕所,以前的那种小便池,可以站很多人。 一般共享锁,使用是在读数据的基础上加
  • 独占锁(写锁) / 共享锁(读锁) / 互斥锁 概念 独占锁:指该锁一次只能被一个线程所持有。对ReentrantLock和Synchronized而言都是独占锁 共享锁:指该锁可以被多个线程锁持有 对ReentrantReadWriteLock其读锁是...
  • 独占锁ReentrantLock的原理 ReentrantLock是使用AQS来实现的,并且根据参数来决定其内部是一个公平还是非公平锁,默认是非公平锁。 public ReentrantLock() { sync = new NonfairSync(); } public ReentrantLock...
  • 1、锁的两种分类方式(1)从数据库系统的角度来看,锁分为以下三种类型: 独占锁(Exclusive Lock) 独占锁锁定的资源只允许进行锁定操作的程序使用,其它任何对它的操作均不会被接受。执行数据更新命令,即INSERT...
  • AQS共享锁与独占锁对比

    千次阅读 2020-03-05 23:23:28
    AQS框架图 上图是AQS框架大致的一些方法,还有一些没有全部的列出来。这里主要是让大家从这张图中,对AQS有一个总体的印象。总的来说AQS框架分为五层从对外暴露的API层到底层的...从流程图中,我们发现独占模式和共...
  • AQS源码分析之独占锁和共享锁

    千次阅读 2017-07-13 15:06:45
    AQS实现机制并不是通过synchronized——给对象加锁实现的,事实上它仅仅是一个工具类!它没有使用更高级的机器指令,也不靠关键字,更不依靠JDK编译时的特殊处理,仅仅作为一个普普通通的类就完成了代码块的访问...
  • mysql for update 独占锁

    2020-04-28 14:22:00
    for update 独占锁,仅适用于InnoDB,并且必须开启事务,在begin与commit之间才生效,锁住的数据不能在事务提交前被修改: 例子1:Select * from table1 where id=xx for update; 行锁; 例子2:select * from ...
  • 共享锁与独占锁简单介绍 共享锁:Shared Locks,简称S锁,可以多个事务共同持有,获得共享锁的事务只能读数据,不能修改数据。 假如事务1⾸先获取了⼀条记录的S锁,如果事务2想要获取这条记录的S锁,那么事务T2也能...
  • 独占锁共享锁

    2018-01-06 15:00:41
    若某事务在数据上持有独占锁定(X), 则其他会话不能读写数据,其他事务不能对该...若某事务在数据上持有共享锁(S),则其他会话只能读取数据、不能写数据,其他事务只能申请对该数据的共享锁、而不能申请独占锁
  • Java-Lock独占锁与共享锁原理

    千次阅读 2018-07-22 09:15:22
    个人理解记录 ReentrantLock基于aqs实现...一般用try finally来实现,相对于synchronized,reentrantlock提供了功能更强大的api,例如超时、可中断、公平、非公平、非阻塞获取等等,ReentrantLock是独占...
  • 主要介绍了PHP session文件独占锁引起阻塞,本文讲解PHP使用默认文件会话处理器时容易导致的阻塞问题解决方法,需要的朋友可以参考下
  • java-通过AQS理解独占锁的实现机制

    千次阅读 2018-11-26 21:11:32
    详细分析如何利用AQS实现独占锁的获取与释放 独占式非公平锁的获取 独占锁默认就是非公平锁,我们要想了解独占锁的获取是否,首先必须知道同步队列为一个有头尾节点的双向链表 1.通过new ReentrantLock().lock();...
  • 其中SHARED和EXCLUSIVE常量分别代表共享模式和独占模式,所谓共享模式是一个允许多条线程同时操作,如信号量Semaphore采用的就是基于AQS的共享模式实现的,而独占模式则是同一个时间段只能有一个线程对共享资源...
  • 悲观:认为数据很容易被修改,所以数据处理...公平与非公平:根据线程抢占的机制,公平表示线程获取的顺序是按照请求的时间的早晚来决定的,即谁先来谁先获取,非公平则并不是,并不按照先后时间来决定
  • 写锁(独占锁):是指该锁一次只能被一个线程锁持有。对ReentrantLock和Sychronized而言都是独占锁。 读锁(共享锁):是指该锁可被多个线程持有。对ReentrantReadWriteLock而言,其读锁是共享锁,其写锁是独占锁。...
  • 独占锁(写锁)/共享锁(读锁)/互斥锁 独占锁:指该锁一次只能被一个线程所持有。对ReentrantLock和Synchronized而言都是独占锁。 共享锁:指该锁可被多个线程所持有。 对ReentrantReadWriteLock其读锁是共享锁,其...
  • Java--独占锁/共享锁

    千次阅读 2018-03-23 21:29:57
    独享和共享在你去...共享:该可被多个线程共有,典型的就是ReentrantReadWriteLock里的读,它的读是可以被共享的,但是它的写确每次只能被独占。对于独享和共享,基于的点在于AQS,AQS的学习在以前就...
  • Java锁(二)ReentrantLock独占锁分析

    千次阅读 2016-04-21 10:59:22
    ReentrantLock的功能是实现代码段的并发访问控制,是一种排它,也就是通常意义上所说的,内部有两种实现NonfairSync和FairSync,公平和非公平,默认采用非公平策略。ReentrantLock的实现不仅可以替代隐式...
  • 共享锁和独占锁 独占锁:也是悲观锁 synchronized和ReentrantLock 共享锁接口: ReadWriteLock接口 共享锁:该锁可被多个线程共有,典型的就是ReentrantReadWriteLock里的读锁,它的读锁是可以被共享的,但是它的写...
  • private function writeFile($file) { // 获取独占锁 if (flock($file,LOCK_EX)) { // 业务处理 // 释放独占锁 flock($file,LOCK_UN); } else { ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 83,343
精华内容 33,337
关键字:

独占锁