-
2019-06-28 09:21:11
转自: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带来困惑。总之,是各有利弊,大师们的思想,还需要仔细揣摩啊!
更多相关内容 -
Java 独占锁与共享锁、公平锁与非公平锁、可重入锁
2021-12-18 17:57:44目录 背景 独占锁与共享锁 独占锁 共享锁 公平锁与非公平锁 公平锁 非公平锁 可重入锁 总结 背景 最近有一些小伙伴会问我一些关于并发相关的问题,在与他们的沟通中,我发现他们对锁的概念很模糊。这部分基础概念的...目录
背景
最近有一些小伙伴会问我一些关于并发相关的问题,在与他们的沟通中,我发现他们对锁的概念很模糊。这部分基础概念的缺失导致他们写的程序经常死锁,还无法bebug。虽然在网上有很多资料,但我还是用一些比较通俗易懂的例子,描述一下,帮助大家理解。
独占锁与共享锁
我发现很多人会把独占锁与公平锁搞混,其实他们不在一个方向上。
独占锁
独占锁是指在同一个时间只能有一个线程占有他,所以具备排他性。像synchronized关键字就是典型的独占锁。
举个栗子:独占锁相当于独间的澡堂,一个人进了这件澡堂,其他人都不能进,只有等他出来。
共享锁
什么是共享锁?
就是指同一时间可以被多个线程占有,像java自带的ReadWriteLock、Semaphore,他们可以设置自己共享的数量。
举个栗子:共享锁相当于一个大型公共澡堂,一开始就设定了能进去洗澡人的数量,比如是10个人,那么你要进去的时候会检查一下有没有满10个,满了你就在门口排队去吧。
公平锁与非公平锁
如果你在排队买奶茶,有个人插队了但是没人制止,你生不生气?他买到了奶茶扬长而去,这公不公平。
公平锁
公平锁就是多个线程去申请锁的使用权的时候,线程会直接进入队列排队,排在前面的可以先获得锁,排在后面的只能等着前面的先用。
举个栗子:有个澡堂,里面已经满了,后面的人想冲进去。但是有个保安站在门口,他让后面想进来的人都排好队,出来一个,就从队伍的前面放一个人进去。
没错,这就很公平。
但是公平锁也会带来其他的缺点,就是需要一个保安去控制,带来的其他开销。如果大家蜂拥而至去抢位置,少了这个保安,会更有效率。没错公平锁的缺点就是会带来更大的开销以及吞吐量下降。
非公平锁
与公平锁对应的就是非公平了,简而言之就是和公平锁反正来,什么不公平来什么。关键字synchronized就是典型的非公平锁。
缺点就是不公平,在某些场景中,特别是每次获取锁后会迅速执行并且释放锁的情况下,非公平锁是可以使用的。假设你洗澡的时间巨长,还有人插我队,这谁能忍得了?
可重入锁
可重入锁的概念很多人容易理解错,他是指同一个线程在申请到锁的情况下,继续申请锁不会阻塞,而是有个计数器记录该线程以及线程申请的次数。
举个栗子:还是单间浴室,但是我有一个洗澡卡,一旦我进了洗澡间就要刷卡,而且出来的时候还需要刷卡退出。那么我一旦进了洗澡间,我可以刷好几次进入卡,这不会阻塞住,因为都是我自己刷的。但是我退出洗澡间的时候我得刷同样次数的退出卡,不然下一个进来的人刷不了进入卡。好理解吗?你也别管我刷几次,反正我刷几次进入,就刷几次退出。
像java的关键字synchronized和ReentrantLock类都是可重入锁。
总结
希望这些简单的栗子可以帮主你理解java一些锁知识,不要把生硬的文字过度理解,跳出文字本身,设想一些生活中的场景,可以帮助我们更好的理解知识。
分享:
知识有两种,其一是我们自己精通的问题;其二是我们知道在哪里找到关于某问题的知识。 ——约翰生
如果本文对你有用的话,请点个赞吧,谢谢!
-
深耕Java多线程 - 共享锁与独占锁
2022-03-25 17:40:20文章目录1. 独占锁2. 共享锁2.1 Semaphore2.2 共享锁使用示例 1. 独占锁 独占锁也叫排他锁、互斥锁、独享锁,是指锁在同一时刻只能被一个线程所持有。一个线程加锁后,任何其他试图...java中的Synchronized内置锁和Ree
问题:
1、Semaphore有什么作用?
2、CyclicBarrier和CountDownLatch的用法及区别
3、三个线程a、b、c并发运行,b,c需要a线程的数据怎么实现?
4、怎么控制同一时间只有 3 个线程运行?1. 独占锁
独占锁也叫排他锁、互斥锁、独享锁,是指锁在同一时刻只能被一个线程所持有。一个线程加锁后,任何其他试图再次加锁的线程都会被阻塞,直到持有锁线程解锁。通俗来说,就是共享资源某一时刻只能有一个线程访问,其余线程阻塞等待。
如果是公平地独占锁,在持有锁线程解锁时,如果有一个以上的线程在阻塞等待,那么最先抢锁的线程被唤醒变为就绪状态去执行加锁操作,其他的线程仍然阻塞等待。
java中的Synchronized内置锁和ReentrantLock显式锁都是独占锁。
2. 共享锁
共享锁就是在同一时刻允许多个线程持有的锁。当然,获得共享锁的线程只能读取临界区的数据,不能修改临界区的数据。
JUC中的共享锁包括Semaphore(信号量)、ReadLock(读写锁)中的读锁、CountDownLatch倒数闩。
2.1 Semaphore
Semaphore用来限制能同时访问共享资源的线程上限。
Semaphore可以用来控制在同一时刻访问共享资源的线程数量,通过协调各个线程以保证共享资源的合理使用。Semaphore维护了一组虚拟许可,它的数量可以通过构造器的参数指定。线程在访问共享资源前必须调用Semaphore的acquire()方法获得许可,如果许可数量为0,该线程就一直阻塞。线程访问完资源后,必须调用Semaphore的release()方法释放许可。更形象的说法是:Semaphore是一个许可管理器。
Semaphore类的主要方法大致如下:
(1) Semaphore(permits)
:构造一个Semaphore实例,初始化其管理的许可数量为permits参数值。(2) Semaphore(permits,fair)
:构造一个Semaphore实例,初始化其管理的许可数量为permits参数值,以及是否以公平模式(fair参数是否为true)进行许可的发放。Semaphore和ReentrantLock类似,Semaphore发放许可时有两种模式:公平模式和非公平模式,默认情况下使用非公平模式。
(3) availablePermits()
:获取Semaphore对象可用的许可数量。(4) acquire()
:当前线程尝试获取Semaphore对象的一个许可。此过程是阻塞的,线程会一直等待Semaphore发放一个许可,直到发生以下任意一件事:- 当前线程获取了一个可用的许可。
- 当前线程被中断,就会抛出InterruptedException异常,并停止等待,继续往下执行。
(5) acquire(permits)
:当前线程尝试阻塞地获取permits个许可。此过程是阻塞的,线程会一直等待Semaphore发放permits个许可。如果没有足够的许可而当前线程被中断,就会抛出InterruptedException异常并终止阻塞。(6) acquireUninterruptibly()
:当前线程尝试阻塞地获取一个许可,阻塞的过程不可中断,直到成功获取一个许可。(7) acquireUninterruptibly(permits)
:当前线程尝试阻塞地获取permits个许可,阻塞的过程不可中断,直到成功获取permits个许可。(8) tryAcquire()
:当前线程尝试获取一个许可。此过程是非阻塞的,它只是进行一次尝试,会立即返回。如果当前线程成功获取了一个许可,就返回true;如果当前线程没有获得许可,就返回false(9) tryAcquire(permits)
:当前线程尝试获取permits个许可。此过程是非阻塞的,它只是进行一次尝试,会立即返回。如果当前线程成功获取了permits个许可,就返回true;如果当前线程没有获得permits个许可,就返回false。(10) tryAcquire(timeout,TimeUnit)
:限时获取一个许可。此过程是阻塞的,会一直等待许可,直到发生以下任意一件事:- 当前线程获取了一个许可,则会停止等待,继续执行,并返回true。
- 当前线程等待timeout后超时,则会停止等待,继续执行,并返回false。
- 当前线程在timeout时间内被中断,则会抛出InterruptedException异常,并停止等待,继续执行。
(11) tryAcquire(permits,timeout,TimeUnit)
:与tryAcquire(timeout,TimeUnit)方法在逻辑上基本相同,不同之处在于:在获取许可的数量上不同,此方法用于获取permits个许可。(12) release()
:当前线程释放一个可用的许可。(13) release(permits)
:当前线程释放permits个可用的许可。(14) drainPermits()
:当前线程获得剩余的所有可用许可。(15) hasQueuedThreads()
:判断当前Semaphore对象上是否存在正在等待许可的线程。(16) getQueueLength()
:获取当前Semaphore对象上正在等待许可的线程数量。共享锁使用示例 :
@Slf4j public class TestSemaphore { public static void main(String[] args) { Semaphore semaphore = new Semaphore(3); for(int i=0;i<10;i++){ new Thread(()->{ try { // 获取许可 semaphore.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } // 睡眠1s try { log.debug("running....."); Thread.sleep(1000); log.debug("end....."); } catch (InterruptedException e) { e.printStackTrace(); }finally { semaphore.release(); } }).start(); } } }
执行结果:
17:36:28.044 [Thread-1] DEBUG com.example.aa.TestSemaphore - running..... 17:36:28.047 [Thread-0] DEBUG com.example.aa.TestSemaphore - running..... 17:36:28.047 [Thread-2] DEBUG com.example.aa.TestSemaphore - running..... 17:36:29.047 [Thread-0] DEBUG com.example.aa.TestSemaphore - end..... 17:36:29.047 [Thread-2] DEBUG com.example.aa.TestSemaphore - end..... 17:36:29.047 [Thread-3] DEBUG com.example.aa.TestSemaphore - running..... 17:36:29.047 [Thread-4] DEBUG com.example.aa.TestSemaphore - running..... 17:36:29.047 [Thread-1] DEBUG com.example.aa.TestSemaphore - end..... 17:36:29.047 [Thread-5] DEBUG com.example.aa.TestSemaphore - running..... 17:36:30.047 [Thread-4] DEBUG com.example.aa.TestSemaphore - end..... 17:36:30.047 [Thread-5] DEBUG com.example.aa.TestSemaphore - end..... 17:36:30.047 [Thread-6] DEBUG com.example.aa.TestSemaphore - running..... 17:36:30.047 [Thread-3] DEBUG com.example.aa.TestSemaphore - end..... 17:36:30.047 [Thread-7] DEBUG com.example.aa.TestSemaphore - running..... 17:36:30.047 [Thread-8] DEBUG com.example.aa.TestSemaphore - running..... 17:36:31.047 [Thread-7] DEBUG com.example.aa.TestSemaphore - end..... 17:36:31.047 [Thread-8] DEBUG com.example.aa.TestSemaphore - end..... 17:36:31.047 [Thread-6] DEBUG com.example.aa.TestSemaphore - end..... 17:36:31.047 [Thread-9] DEBUG com.example.aa.TestSemaphore - running..... 17:36:32.048 [Thread-9] DEBUG com.example.aa.TestSemaphore - end.....
2.2 CountDownLatch
用来进行线程同步协作,等待所有线程完成倒计时。 其中构造参数用来初始化等待计数值,await() 用来等待计数归零,countDown() 用来让计数减一。
CountDownLatch可以指定一个计数值,在并发环境下由线程进行减一操作,当计数值变为0之后,被await方法阻塞的线程将会唤醒。通过CountDownLatch可以实现线程间的计数同步。
@Slf4j public class TestCountDownLatch { public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(3); new Thread(()->{ log.debug("begin..."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // 计数减1 countDownLatch.countDown(); log.debug("end..."); }).start(); new Thread(()->{ log.debug("begin..."); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } // 计数减1 countDownLatch.countDown(); log.debug("end..."); }).start(); new Thread(()->{ log.debug("begin..."); try { Thread.sleep(1500); } catch (InterruptedException e) { e.printStackTrace(); } // 计数减1 countDownLatch.countDown(); log.debug("end..."); }).start(); log.debug("waiting..."); // await() 用来等待计数归零 countDownLatch.await(); // 当计数值变为0之后,被await方法阻塞的线程将会唤醒 log.debug("waiting end...."); } }
执行结果:
19:23:34.930 [pool-1-thread-2] DEBUG com.example.aa.TestCountDownLatch - begin... 19:23:34.930 [pool-1-thread-3] DEBUG com.example.aa.TestCountDownLatch - begin... 19:23:34.930 [pool-1-thread-1] DEBUG com.example.aa.TestCountDownLatch - begin... 19:23:34.932 [pool-1-thread-4] DEBUG com.example.aa.TestCountDownLatch - waiting... 19:23:35.933 [pool-1-thread-1] DEBUG com.example.aa.TestCountDownLatch - end...2 19:23:36.432 [pool-1-thread-3] DEBUG com.example.aa.TestCountDownLatch - end...1 19:23:36.933 [pool-1-thread-2] DEBUG com.example.aa.TestCountDownLatch - end...0 19:23:36.933 [pool-1-thread-4] DEBUG com.example.aa.TestCountDownLatch - waiting end....
可以配合线程池使用,改进如下:
@Slf4j public class TestCountDownLatch { public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(3); ExecutorService executorService = Executors.newFixedThreadPool(4); executorService.submit(()->{ log.debug("begin..."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // 计数减1 countDownLatch.countDown(); log.debug("end...{}",countDownLatch.getCount()); }); executorService.submit(()->{ log.debug("begin..."); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } // 计数减1 countDownLatch.countDown(); log.debug("end...{}",countDownLatch.getCount()); }); executorService.submit(()->{ log.debug("begin..."); try { Thread.sleep(1500); } catch (InterruptedException e) { e.printStackTrace(); } // 计数减1 countDownLatch.countDown(); log.debug("end...{}",countDownLatch.getCount()); }); executorService.submit(()->{ log.debug("waiting..."); // await() 用来等待计数归零 try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } // 当计数值变为0之后,被await方法阻塞的线程将会唤醒 log.debug("waiting end...."); }); } }
结合上述示例的运行结果,梳理一下CountDownLatch的使用步骤:
(1)创建倒数闩,初始化CountDownLatch时设置倒数的总次数,比如为3。
(2)等待线程调用倒数闩的await()方法阻塞自己,等待倒数闩的计数器数值为0(倒数线程全部执行结束)。
(3)倒数线程执行完,调用CountDownLatch.countDown()方法将计数器数值减一。
2.3 CyclicBarrie
用来进行线程协作,等待线程满足某个计数。构造时设置『计数个数』,每个线程执 行到某个需要“同步”的时刻调用 await() 方法进行等待,当等待的线程数满足『计数个数』时,继续执行
@Slf4j public class TestCountDownLatch { public static void main(String[] args) throws InterruptedException { CyclicBarrier cb = new CyclicBarrier(2); // 个数为2时才会继续执行 new Thread(()->{ System.out.println("线程1开始.."+new Date()); try { cb.await(); // 当个数不足时,等待 } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } System.out.println("线程1继续向下运行..."+new Date()); }).start(); new Thread(()->{ System.out.println("线程2开始.."+new Date()); try { Thread.sleep(2000); } catch (InterruptedException e) { } try { cb.await(); // 2 秒后,线程个数够2,继续运行 } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } System.out.println("线程2继续向下运行..."+new Date()); }).start(); } }
执行结果:
线程1开始..Mon Mar 28 19:32:21 CST 2022 线程2开始..Mon Mar 28 19:32:21 CST 2022 线程2继续向下运行...Mon Mar 28 19:32:23 CST 2022 线程1继续向下运行...Mon Mar 28 19:32:23 CST 2022
CyclicBarrier 与 CountDownLatch 的主要区别在于 CyclicBarrier 是可以重用的,CyclicBarrier 可以被比 喻为『人满发车』
Semaphore、CountDownLatch二者都是基于共享锁实现的,用于在线程之间进行操作同步的工具类。JUC的同步工具类一共有3个:Semaphore、CountDownLatch和CyclicBarrier。
-
独占锁(写锁)/共享锁(读锁)/互斥锁
2021-03-16 15:08:36对ReentrantLock和Synchronized而言都是独占锁共享锁:指该锁可被多个线程所持有。对ReentrantReadWriteLock其读锁是共享锁,其写锁是独占锁。读锁的共享锁可保证并发读是非常高效的,读写,写读,写写的过程是互斥...独占锁:指该锁一次只能被一个线程所持有。对ReentrantLock和Synchronized而言都是独占锁
共享锁:指该锁可被多个线程所持有。对ReentrantReadWriteLock其读锁是共享锁,其写锁是独占锁。
读锁的共享锁可保证并发读是非常高效的,读写,写读,写写的过程是互斥的。
使用方法
声明一个读写锁
如果需要独占锁则加从可重入读写锁里得到写锁
写锁demo
如果需要共享锁则加从可重入读写锁里得到读锁
读锁demo
ReentrantReadWriteLock实现原理简单分析
ReentrantReadWriteLock 的核心是由一个基于AQS的同步器 Sync 构成,然后由其扩展出 ReadLock (共享锁), WriteLock (排它锁)所组成。
并且从 ReentrantReadWriteLock 的构造函数中可以发现 ReadLock 与 WriteLock 使用的是同一个Sync
Sync的实现
sync 是读写锁实现的核心, sync 是基于AQS实现的,在AQS中核心是state字段和双端队列,那么一个一个问题来分析。
Sync是如何同时表示读锁与写锁?
清单2:读写锁状态获取
static final int SHARED_SHIFT = 16;
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
/** Returns the number of shared holds represented in count /
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
/* Returns the number of exclusive holds represented in count */
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
从代码中获取读写状态可以看出其是把 state(int32位) 字段分成高16位与低16位,其中高16位表示读锁个数,低16位表示写锁个数
一个线程获取到了写锁,并且重入了两次,低16位是3,线程又获取了读锁,并且重入了一次,高16位就是2
读锁的写锁的获取主要调用AQS的相关Acquire方法,其释放主要用了相关Release方法,其中关于AQS的升级降级锁个数的调整还用到了CAS;
-
Java常见锁(公平锁、非公平锁、可重入锁、自旋锁、独占锁、共享锁)
2021-04-01 15:34:58Java常见锁(公平锁、非公平锁、可重入锁、自旋锁、独占锁、共享锁)一、公平锁和非公平锁二、java锁之可重入锁(递归锁)三、自旋锁四、独占锁(写锁)/ 共享锁(读锁)/ 互斥锁五、八锁问题 一、公平锁和非公平锁 ... -
浅析Sql server锁,独占锁,共享锁,更新锁,乐观锁,悲观锁
2020-09-10 19:00:21以下是对Sql server锁,独占锁,共享锁,更新锁,乐观锁,悲观锁进行了详细的介绍,需要的朋友可以过来参考下 -
Java面试——共享锁和独占锁
2020-07-27 23:57:13将这两个锁之前,我先讲下上一章遗留的...共享锁和独占锁 共享锁,顾名思义,就是这个锁是共享的,咱们能一起使用这个锁。这个就像进男厕所,以前的那种小便池,可以站很多人。 一般共享锁,使用是在读数据的基础上加 -
mysql学习-7.独占锁和共享锁
2021-06-29 14:16:35如果未加锁就会添加一个独占锁,包含了自己的trx_id和状态和这行数据关联起来 第二事务过来的时候判断到有锁了,那么他也加一个独占锁在后面排队只是状态是待执行的状态 第一个事务执行完了之后就会检查这行数据是否... -
java并发-独占锁和共享锁
2019-10-10 18:16:20java并发包提供的加锁模式分为独占锁和共享锁,独占锁模式下,每次只能有一个线程能持有锁,ReentrantLock就是以独占方式实现的互斥锁。共享锁,则允许多个线程同时获取锁,并发访问 共享资源,如:ReadWriteLock。... -
Java 独占锁|共享锁|互斥锁
2020-02-22 21:57:15Java 中 ReentrantLock 和 synchronized 都是独占锁。 共享锁 又叫读锁,指该锁可以被多个线程所持有。Java 中 ReentrantReadWriteLock 其读锁是共享锁,其写锁是独占锁。 读锁的共享锁可保证并发读是非常高效的... -
基础篇:独占锁、共享锁、公平锁、非公平锁,叫我如何分得清
2019-12-20 20:00:31java并发包提供的加锁模式分为独占锁和共享锁,独占锁模式下,每次只能有一个线程能持有锁,ReentrantLock就是以独占方式实现的互斥锁。共享锁,则允许多个线程同时获取锁,并发访问 共享资源,如:ReadWriteLock。... -
Java-Lock独占锁与共享锁原理
2018-07-22 09:15:22ReentrantLock在使用时需要显式的获取和释放锁,一般用try finally来实现,相对于synchronized,reentrantlock提供了功能更强大的api,例如超时锁、可中断锁、公平锁、非公平锁、非阻塞锁获取等等,ReentrantLock是... -
java 锁(七):独享锁VS共享锁
2021-03-09 21:14:48独享锁和共享锁同样是一种概念。我们先介绍一下具体的概念,然后通过ReentrantLock和ReentrantReadWriteLock的源码来介绍独享锁和共享锁。独享锁也叫排他锁,是指该锁一次只能被一个线程锁持有。如果线程T对数据A... -
Java中的锁:排他锁(独占锁)/共享锁
2021-06-23 17:08:39Java代码层面的这个锁,是针对某一条数据的。 其次,怎么实现这个锁? 第一,需要一个公共锁空间,来保存锁。这样用户A和用户B在修改数据前先查一下对应数据有没有加锁。 第二,锁包含的信息一定是能唯一标识要... -
独占锁(写锁) / 共享锁(读锁) / 互斥锁
2021-03-16 15:08:39对ReentrantLock和Synchronized而言都是独占锁共享锁:指该锁可以被多个线程锁持有对ReentrantReadWriteLock其读锁是共享,其写锁是独占写的时候只能一个人写,但是读的时候,可以多个人同时读为什么会有写锁和读锁... -
java-15种锁之独占锁(写)/共享锁(读)/互斥锁
2019-07-02 01:00:58对ReentrantLock和Sychronized而言都是独占锁。 读锁(共享锁):是指该锁可被多个线程持有。对ReentrantReadWriteLock而言,其读锁是共享锁,其写锁是独占锁。读锁的共享性可保证并发读是非常高效的,读写、写读、... -
AQS源码分析之独占锁和共享锁
2017-07-13 15:06:45AQS实现锁机制并不是通过synchronized——给对象加锁实现的,事实上它仅仅是一个工具类!它没有使用更高级的机器指令,也不靠关键字,更不依靠JDK编译时的特殊处理,仅仅作为一个普普通通的类就完成了代码块的访问... -
Java - 独占锁(写锁)/共享锁(读锁)/互斥锁
2019-12-25 22:18:39Java - 独占锁(写锁)/共享锁(读锁)/互斥锁 独占锁(写锁): 共享锁: 多个线程同时读一个资源没有任何问题,所以为了满足并发量,读取共享资源应该可以同时进行。 但是 如果有一个线程想去写共享资源来,就不... -
Java中的锁机制——读写锁(共享锁/独占锁)
2020-06-01 10:21:47我们经常听到的独占锁其实就是写锁:一次只能被一个线程占有;共享锁其实就是读锁:多个线程可以同时占有 我们举个例子,先来看看不加读写锁的情况 package com.lt.ReadWriteLock; import java.util.HashMap; ... -
JAVA 锁
2021-03-06 14:19:50都是依靠AbstractQueuedSynchronizer(AQS)实现的,这个东西之前的文章讲过,在这个类里有两种锁,一种是共享锁(作用是让多个线程可以同时拥有锁,也就是允许多个线程同时访问一个共享资源),一种是独占锁(某一时刻... -
AQS共享锁与独占锁对比
2020-03-05 23:23:28AQS框架图 上图是AQS框架大致的一些方法,还有一些没有全部的列出来。这里主要是让大家从这张图...共享模式和独占模式流程图对比 独占模式流程图 共享模式流程图 相同点 从流程图中,我们发现独占模式和共... -
Java锁(三):Semaphore共享锁详解
2022-03-29 21:48:24一、基于AQS实现的锁 AQS(AbstractQueuedSynchronizer) 是Java...ReentrantReadWriteLock:读写锁,可共享也可独占锁,读是共享锁,写是独占锁,也实现了公平锁和非公平锁。 Semaphore:信号锁,共享锁,也实现了公 -
Java--独占锁/共享锁
2018-03-23 21:29:57独享锁和共享锁在你去读C.U.T包下的ReeReentrantLock和ReentrantReadWriteLock你就会发现,它俩一个是独享一个是共享锁。独享锁:该锁每一次只能被一个线程所持有。共享锁:该锁可被多个线程共有,典型的就是... -
独占锁和共享锁
2017-08-15 20:54:39http://www.infoq.com/cn/articles/jdk1.8-abstractqueuedsynchronizerhttp://ifeve.com/java-synchronousqueue/ http://blog.csdn.net/longeremmy/article/details/8231184 -
悲观锁,乐观锁,公平锁非公平锁,独占锁,共享锁,可重入锁,自旋锁
2020-05-10 21:46:44乐观锁:乐观锁是相对悲观锁来说的,认为数据在一般情况下不会被修改,在访问记录前不会加锁,在对数据进行提交更新时,才会正式判断数据是否发生改变并返回对应信息,让用户自己决定怎么处理,一般通过版本号和CAS... -
Java 并发编程:AQS 的互斥锁与共享锁
2020-12-22 11:21:09但是多核多线程也会带来很多并发问题,其中很重要的一个问题是数据竞争,数据竞争即多个线程同时访问共享数据而导致了数据冲突(不正确)。数据竞争如果没处理好则意味着整个业务逻辑可能出错,所以在高并发环境中... -
Java面试之JUC系列:独占锁(写锁) / 共享锁(读锁) / 互斥锁
2020-11-26 16:40:56独占锁(写锁) / 共享锁(读锁) / 互斥锁 概念 独占锁:指该锁一次只能被一个线程所持有。对ReentrantLock和Synchronized而言都是独占锁 共享锁:指该锁可以被多个线程锁持有 对ReentrantReadWriteLock其读锁是...