栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java锁的简单梳理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java锁的简单梳理

重量级锁与轻量级锁

​ 轻量级锁一般使用的是cas原理,进行自旋来获取锁,如果一直有多个线程发生竞争的话,会发生CPU过高的情况。

​ 重量级锁一般使用Synchronized或者ReentrantLock,ReentrantLock底层原理是AQS。Synchronized有锁升级的过程,ReentrantLock可操作性更强,比如选择公平锁或者非公平锁(饿死现象),以及手动释放等。

CountDownLatch:创建时的参数为计数器的值

​ await()方法:阻塞等待执行,aqs

​ countDown()方法:对计数器中的值进行递减,减到0唤醒所有因调用await方法而被阻塞的线程。

​ 相比于使用join方法来实现线程间同步,CountDownLatch更具有灵活性和方便性。并且调用子程序的join()方法后,该线程会一直被阻塞直到子程序运行完毕,而CountDownLatch是使用计数器来允许子线程运行完毕或者运行中递减计数,而没必要一定等待线程结束,另外,使用线程池来管理线程时,一般都是直接添加到Runable到线程池,这时候没有办法再调用线程的join方法。

**CyclicBarrier :**回环屏障,也是基于aqs

​ CyclicBarrir构造器中parties

​ await()方法:当前线程会被阻塞,直到parties个线程都调用了await方法,或者被中断。当count为0时,重新设为parties。

CycleBarrier与ountDownLatch 的不同在于,前者是可以复用 的,并且前者特别适合分段任务有序执行的场景。然后分析了 CycleBarrier 其通独占锁 ReentrantLock 实现计数器原子性更新,并使用条件变量队列来实现线程同步。

**Semaphore:**信号量,构造器入参为信号量计数,以及是否公平策略,默认非公平。如果为公平锁,底层为LockSupport

​ acqire()方法:非公平,先尝试能否获取到信号量,非公平则是先看aqs阻塞队列中有没有其他线程,没有在尝试获取,如果没有获取到,则当前线程会被放入 AQS 的阻塞队列。

​ acqire(int i)方法:

​ release()方法:该方法的作用 Semaphore 信号量值增加 ,如果当前有线程因为调用aquire 方法被阻塞 被放入了 AQS 的阻塞队列,则会根据公平策略选择一个信号量个数能被满足的线程进行激活, 激活的线程会尝试获取刚增加的信号量。

​ release(int i)方法:

​ Semaphor 完全可以达到CountDownLatch 的效果,但是 Semaphore 的计数器是不可以自动重置的, 不过通过变相地改变 aquire 方法的参数还是可以实现 CycleBarrier 的功能的 。 Semaphore 也是使用 AQS 现的,并且获取信号量时有公平策略和非公平策略之分。

线程池中Future与get方法可能出现的问题

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 1,
                TimeUnit.SECONDS, new ArrayBlockingQueue<>(1), new ThreadPoolExecutor.AbortPolicy());

        Future submit1 = threadPoolExecutor.submit(() -> {
            try {
                TimeUnit.SECONDS.sleep(5);
                System.out.println("8777");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Future submit2 = threadPoolExecutor.submit(() -> System.out.println("8989"));
        Future submit3 = null;
        try {
            submit3=threadPoolExecutor.submit(() -> System.out.println("9999"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(submit1.get());
        System.out.println(submit2.get());
        System.out.println(submit3!=null?submit3.get():null);
        threadPoolExecutor.shutdown();

在线程池中使用 FutureTask 时, 当拒绝策略为 DiscardPolicy和DiscardOldestPolicy 时,在被拒绝的任务FutureTask 对象上调用 get() 方法会导致调用线程一直阻塞,所以在日常开发中尽量使用带超时参数的 get 方法以避免线程一直阻塞。原因是这两个拒绝策略返回的是New状态的Future对象。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/390080.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号