精华内容
下载资源
问答
  • 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带来困惑。总之,是各有利弊,大师们的思想,还需要仔细揣摩啊!

    更多相关内容
  • 目录 背景 独占锁共享锁 独占锁 共享锁 公平锁与非公平锁 公平锁 非公平锁 可重入锁 总结 背景 最近有一些小伙伴会问我一些关于并发相关的问题,在与他们的沟通中,我发现他们对锁的概念很模糊。这部分基础概念的...

    目录

    背景

    独占锁与共享锁

    独占锁

    共享锁

    公平锁与非公平锁

    公平锁

    非公平锁

    可重入锁

    总结


    背景

    最近有一些小伙伴会问我一些关于并发相关的问题,在与他们的沟通中,我发现他们对锁的概念很模糊。这部分基础概念的缺失导致他们写的程序经常死锁,还无法bebug。虽然在网上有很多资料,但我还是用一些比较通俗易懂的例子,描述一下,帮助大家理解。

    独占锁与共享锁

    我发现很多人会把独占锁与公平锁搞混,其实他们不在一个方向上。

    独占锁

    独占锁是指在同一个时间只能有一个线程占有他,所以具备排他性。像synchronized关键字就是典型的独占锁。

    举个栗子:独占锁相当于独间的澡堂,一个人进了这件澡堂,其他人都不能进,只有等他出来。

    共享锁

    什么是共享锁?

    就是指同一时间可以被多个线程占有,像java自带的ReadWriteLock、Semaphore,他们可以设置自己共享的数量。

    举个栗子:共享锁相当于一个大型公共澡堂,一开始就设定了能进去洗澡人的数量,比如是10个人,那么你要进去的时候会检查一下有没有满10个,满了你就在门口排队去吧。

    公平锁与非公平锁

    如果你在排队买奶茶,有个人插队了但是没人制止,你生不生气?他买到了奶茶扬长而去,这公不公平。

    公平锁

    公平锁就是多个线程去申请锁的使用权的时候,线程会直接进入队列排队,排在前面的可以先获得锁,排在后面的只能等着前面的先用。

    举个栗子:有个澡堂,里面已经满了,后面的人想冲进去。但是有个保安站在门口,他让后面想进来的人都排好队,出来一个,就从队伍的前面放一个人进去。

    没错,这就很公平。

    但是公平锁也会带来其他的缺点,就是需要一个保安去控制,带来的其他开销。如果大家蜂拥而至去抢位置,少了这个保安,会更有效率。没错公平锁的缺点就是会带来更大的开销以及吞吐量下降。

    非公平锁

    与公平锁对应的就是非公平了,简而言之就是和公平锁反正来,什么不公平来什么。关键字synchronized就是典型的非公平锁。

    缺点就是不公平,在某些场景中,特别是每次获取锁后会迅速执行并且释放锁的情况下,非公平锁是可以使用的。假设你洗澡的时间巨长,还有人插我队,这谁能忍得了?

    可重入锁

    可重入锁的概念很多人容易理解错,他是指同一个线程在申请到锁的情况下,继续申请锁不会阻塞,而是有个计数器记录该线程以及线程申请的次数。

    举个栗子:还是单间浴室,但是我有一个洗澡卡,一旦我进了洗澡间就要刷卡,而且出来的时候还需要刷卡退出。那么我一旦进了洗澡间,我可以刷好几次进入卡,这不会阻塞住,因为都是我自己刷的。但是我退出洗澡间的时候我得刷同样次数的退出卡,不然下一个进来的人刷不了进入卡。好理解吗?你也别管我刷几次,反正我刷几次进入,就刷几次退出。

    像java的关键字synchronized和ReentrantLock类都是可重入锁。

    总结

    希望这些简单的栗子可以帮主你理解java一些锁知识,不要把生硬的文字过度理解,跳出文字本身,设想一些生活中的场景,可以帮助我们更好的理解知识。

    分享:

            知识有两种,其一是我们自己精通的问题;其二是我们知道在哪里找到关于某问题的知识。                                                                                        ——约翰生

    如果本文对你有用的话,请点个赞吧,谢谢!

    展开全文
  • 文章目录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。

    展开全文
  • 对ReentrantLockSynchronized而言都是独占锁共享锁:指该锁可被多个线程所持有。对ReentrantReadWriteLock其读锁是共享锁,其写锁是独占锁。读锁的共享锁可保证并发读是非常高效的,读写,写读,写写的过程是互斥...

    独占锁:指该锁一次只能被一个线程所持有。对ReentrantLock和Synchronized而言都是独占锁

    共享锁:指该锁可被多个线程所持有。对ReentrantReadWriteLock其读锁是共享锁,其写锁是独占锁。

    读锁的共享锁可保证并发读是非常高效的,读写,写读,写写的过程是互斥的。

    使用方法

    9cd7f8d514b9

    声明一个读写锁

    如果需要独占锁则加从可重入读写锁里得到写锁

    9cd7f8d514b9

    写锁demo

    如果需要共享锁则加从可重入读写锁里得到读锁

    9cd7f8d514b9

    读锁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常见锁(公平锁、非公平锁、可重入锁、自旋锁、独占锁共享锁)一、公平锁和非公平锁二、java锁之可重入锁(递归锁)三、自旋锁四、独占锁(写锁)/ 共享锁(读锁)/ 互斥锁五、八锁问题 一、公平锁和非公平锁 ...
  • 以下是对Sql server锁,独占锁,共享锁,更新锁,乐观锁,悲观锁进行了详细的介绍,需要的朋友可以过来参考下
  • 将这两个锁之前,我先讲下上一章遗留的...共享锁和独占锁 共享锁,顾名思义,就是这个锁是共享的,咱们能一起使用这个锁。这个就像进男厕所,以前的那种小便池,可以站很多人。 一般共享锁,使用是在读数据的基础上加
  • 如果未加锁就会添加一个独占锁,包含了自己的trx_id状态这行数据关联起来 第二事务过来的时候判断到有锁了,那么他也加一个独占锁在后面排队只是状态是待执行的状态 第一个事务执行完了之后就会检查这行数据是否...
  • java并发包提供的加锁模式分为独占锁和共享锁独占锁模式下,每次只能有一个线程能持有锁,ReentrantLock就是以独占方式实现的互斥锁。共享锁,则允许多个线程同时获取锁,并发访问 共享资源,如:ReadWriteLock。...
  • Java 中 ReentrantLock synchronized 都是独占锁共享锁 又叫读锁,指该锁可以被多个线程所持有。Java 中 ReentrantReadWriteLock 其读锁是共享锁,其写锁是独占锁。 读锁的共享锁可保证并发读是非常高效的...
  • java并发包提供的加锁模式分为独占锁和共享锁独占锁模式下,每次只能有一个线程能持有锁,ReentrantLock就是以独占方式实现的互斥锁。共享锁,则允许多个线程同时获取锁,并发访问 共享资源,如:ReadWriteLock。...
  • Java-Lock独占锁共享锁原理

    千次阅读 2018-07-22 09:15:22
    ReentrantLock在使用时需要显式的获取释放,一般用try finally来实现,相对于synchronized,reentrantlock提供了功能更强大的api,例如超时、可中断、公平、非公平、非阻塞获取等等,ReentrantLock是...
  • 独享锁和共享锁同样是一种概念。我们先介绍一下具体的概念,然后通过ReentrantLock和ReentrantReadWriteLock的源码来介绍独享锁和共享锁。独享锁也叫排他锁,是指该锁一次只能被一个线程锁持有。如果线程T对数据A...
  • Java中的锁:排他锁(独占锁)/共享锁

    千次阅读 2021-06-23 17:08:39
    Java代码层面的这个,是针对某一条数据的。 其次,怎么实现这个? 第一,需要一个公共空间,来保存。这样用户A用户B在修改数据前先查一下对应数据有没有加锁。 第二,包含的信息一定是能唯一标识要...
  • 对ReentrantLock和Synchronized而言都是独占锁共享锁:指该锁可以被多个线程锁持有对ReentrantReadWriteLock其读锁是共享,其写锁是独占写的时候只能一个人写,但是读的时候,可以多个人同时读为什么会有写锁和读锁...
  • 对ReentrantLockSychronized而言都是独占锁。 读锁(共享锁):是指该锁可被多个线程持有。对ReentrantReadWriteLock而言,其读锁是共享锁,其写锁是独占锁。读锁的共享性可保证并发读是非常高效的,读写、写读、...
  • AQS源码分析之独占锁和共享锁

    千次阅读 2017-07-13 15:06:45
    AQS实现机制并不是通过synchronized——给对象加锁实现的,事实上它仅仅是一个工具类!它没有使用更高级的机器指令,也不靠关键字,更不依靠JDK编译时的特殊处理,仅仅作为一个普普通通的类就完成了代码块的访问...
  • Java - 独占锁(写锁)/共享锁(读锁)/互斥锁 独占锁(写锁): 共享锁: 多个线程同时读一个资源没有任何问题,所以为了满足并发量,读取共享资源应该可以同时进行。 但是 如果有一个线程想去写共享资源来,就不...
  • 我们经常听到的独占锁其实就是写锁:一次只能被一个线程占有;共享锁其实就是读锁:多个线程可以同时占有 我们举个例子,先来看看不加读写锁的情况 package com.lt.ReadWriteLock; import java.util.HashMap; ...
  • JAVA

    2021-03-06 14:19:50
    都是依靠AbstractQueuedSynchronizer(AQS)实现的,这个东西之前的文章讲过,在这个类里有两种锁,一种是共享锁(作用是让多个线程可以同时拥有锁,也就是允许多个线程同时访问一个共享资源),一种是独占锁(某一时刻...
  • AQS共享锁独占锁对比

    千次阅读 2020-03-05 23:23:28
    AQS框架图 上图是AQS框架大致的一些方法,还有一些没有全部的列出来。这里主要是让大家从这张图...共享模式和独占模式流程图对比 独占模式流程图 共享模式流程图 相同点 从流程图中,我们发现独占模式共...
  • 一、基于AQS实现的锁 AQS(AbstractQueuedSynchronizer) 是Java...ReentrantReadWriteLock:读写锁,可共享也可独占锁,读是共享锁,写是独占锁,也实现了公平锁和非公平锁。 Semaphore:信号锁,共享锁,也实现了公
  • Java--独占锁/共享锁

    千次阅读 2018-03-23 21:29:57
    独享锁和共享锁在你去读C.U.T包下的ReeReentrantLock和ReentrantReadWriteLock你就会发现,它俩一个是独享一个是共享锁。独享锁:该锁每一次只能被一个线程所持有。共享锁:该锁可被多个线程共有,典型的就是...
  • 独占锁和共享锁

    2017-08-15 20:54:39
    http://www.infoq.com/cn/articles/jdk1.8-abstractqueuedsynchronizerhttp://ifeve.com/java-synchronousqueue/ http://blog.csdn.net/longeremmy/article/details/8231184
  • 乐观:乐观是相对悲观来说的,认为数据在一般情况下不会被修改,在访问记录前不会加锁,在对数据进行提交更新时,才会正式判断数据是否发生改变并返回对应信息,让用户自己决定怎么处理,一般通过版本号CAS...
  • 但是多核多线程也会带来很多并发问题,其中很重要的一个问题是数据竞争,数据竞争即多个线程同时访问共享数据而导致了数据冲突(不正确)。数据竞争如果没处理好则意味着整个业务逻辑可能出错,所以在高并发环境中...
  • 独占锁(写锁) / 共享锁(读锁) / 互斥锁 概念 独占锁:指该锁一次只能被一个线程所持有。对ReentrantLockSynchronized而言都是独占锁 共享锁:指该锁可以被多个线程锁持有 对ReentrantReadWriteLock其读锁是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 43,133
精华内容 17,253
关键字:

java独占锁和共享锁

java 订阅