Java并发基础Java中的锁

锁是用来控制多个线程访问共享资源的方式,一个锁能够防止多个线程同时访问共享资源。

Lock

在**Lock接口出现之前,Java通过synchronized关键字实现锁功能,JDK 1.5之后,在并发包中新增了Lock接口来实现锁功能,有与synchronized关键字类似功能,只是在使用时需要显示的获取锁和释放锁,拥有了锁释放和获取的可操作性、可中断性等synchronized关键字不具备的特性。在使用synchronized关键字会隐式的获取锁和释放锁,但锁的获取和释放固化,即先获取后释放。Lock接口的实现基本上是通过聚合一个同步器(AQS**)的子类来完成线程访问控制。

Lock接口的使用方式:

Lock lock = new ReentrantLock();
lock.lock();
try{
}finally{
	lock.unlock()
}

比较synchronized和ReentrantLock

  • 锁的实现

    synchronized是JVM实现的,而ReentrantLock是JDK实现

  • 性能新版Java对synchronized进行了很多的优化,synchronized与ReentrantLock大致相同。

  • 等待可中断

    当持有锁的线程长期不释放锁,正在等待的线程可以选择放弃等待,改为处理其他事情。ReentrantLock可以中断,而synchronized不可以中断

  • 公平锁

    公平锁是指多个线程在等待同一锁时,必须按照申请的时间顺序来依次获得锁。synchronized中的锁是非公平的,ReentrantLock默认也是非公平,但也是可以公平的

  • 锁绑定多个条件

    一个ReentrantLock可以同时绑定多个Condition对象

如何选择呢?

优先使用synchronized,除非需要使用ReentrantLock的高级功能,因为synchronized是JVM实现的一种锁机制,JVM原生的支持,而ReentrantLock不是所有的JDK都支持,synchronized不用担心没有锁而造成死锁问题,JVM会确保锁的释放。
上面的代码示例中要注意:获取锁的过程不要写在**try**中,因为在获取锁时发生异常,异常抛出的同时,也会导致锁无故释放。

重入锁

重入锁ReentrantLock,支持重进入的锁,表示该锁功能支持一个线程对资源的重复加锁。

实现重进入

重进入是指任意线程在获取锁之后能够再次获取该锁而不会被锁所阻塞,这个特性需要解决两个问题:

  • 线程再次获取锁:所需要去识别获取锁的线程是否为当前占据锁的线程,如果是则再次成功获取。
  • 锁的最终释放:线程重复n次获取锁,随后第n次释放该锁后,其他线程能够获取到该锁。锁的最终释放要求锁对于获取进行计数自增,计数表示当前锁被重复获取的次数,而锁被释放时,计数自减当计数等于0时表示已经释放成功。

重入锁是通过组合自定义**同步器**来实现锁的获取和释放。获取同步状态的代码如下:

final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

通过判断当前线程是否为获取锁的线程来决定获取操作是否成功,如果是获取锁的线程再次请求,则将同步状态值进行增加并返回true,表示获取同步状态成功。

读写锁

读写锁维护一对锁,一个读锁和一个写锁,通过分离读锁和写锁使得并发性相比一般的排他锁有了更大的提升,读写锁的性能都会比排它锁好,因为大多数场景读操作对于写操作,在这样的情况下读写锁能够提供排它锁更好的并发性和吞吐量,

读写锁的实现

  • 读写状态的设计

    读写锁同样依赖自定义同步器来实现同步功能,而读写状态就是其同步器的同步状态。读写锁的自定义同步器需要在同步同步状态上维护多个读线程和一个写线程的状态,状态的设计成为读写锁实现的关键。

    如果在一个整型变量上维护多种状态,就一定需要“按位切割使用”这个变量,读写锁将变量切分成两个部分,高16为表示读,低16位表示写

  • 写锁的获取与释放

    写锁是一个支持重进入的排它锁,如果当前线程已经获取了写锁,则增加写状态。如果当前线程在获取写锁时,读锁已经被获取或者该线程不是已经获取写锁的线程,则当前线程进入等待状态。写锁的释放与ReentrantLock的释放过程基本相似,每次释放均减少写状态,当写状态为0时表示写锁已经被释放,从而等待读写线程能够继续访问读写锁,同时前次的写线程的修改对后续读写线程可见。

  • 读锁的获取与释放

    读锁是一个支持重进入的共享锁,能够被多个线程同时获取,在没有其他的写线程访问时,读锁总会被成功的获取,而所做的只是增加读状态,如果当前线程已经获取了读锁,则增加读状。如果当前线程在获取读锁时,写锁已被其他线程获取,则进入等待状态。

  • 锁降级

    锁降级指的是写锁降级为读锁。如果当前线程拥有写锁,然后将其释放,最后在获取读锁,这种分段完成的过程不能称为锁降级。锁降级是指把持住写锁,再获取到读锁,随后释放写锁的过程。锁降级中读锁释放主要是为了保证数据的可见性。

队列同步器

队列同步器**AbstractQueuedSynchronizer,是用来构建锁或者其他同步组件的基本框架,使用一个int**成员变量表示同步状态,通过内置FIFO队列来完成资源的获取线程的排队工作。

同步器是实现锁的关键,在锁的实现中聚合同步器,利用同步器实现锁的语义。二者的关系是:锁是面向使用者,定义了使用者与锁交互的接口,隐藏了实现细节;同步器则面向锁的实现者,简化了锁的实现方式,屏蔽了同步状态管理、线程的排队、等待与唤醒等底层操作。同步器的主要使用方式是继承,子类通过继承同步器并实现它的抽象方法来管理同步器状态。

队列同步器的实现分析

同步队列

同步器依赖内部的同步队列来完成同步状态的管理,当前线程获取同步状态失败时,同步器会将当前线程以及等待状态的信息够造成一个节点将其加入到同步队列,同时会阻塞当前线程,当同步状态释放时,会把首节点中的线程唤醒,使其再次尝试获取同步器状态。

节点是构成同步队列的基础,同步器拥有首节点和尾节点,没有成功获取同步状态的线程会成为节点加入到该队列的尾部。

JAVA并发编程与高并发面试

04-28
[JAVA工程师必会知识点之并发编程] 1、现在几乎100%的公司面试都必须面试并发编程,尤其是互联网公司,对于并发编程的要求更高,并发编程能力已经成为职场敲门砖。 2、现在已经是移动互联和大数据时代,对于应用程序的性能、处理能力、处理时效性要求更高了,传统的串行化编程无法充分利用现有的服务器性能。 3、并发编程是几乎所有框架的底层基础,掌握好并发编程更有利于我们学习各种框架。想要让自己的程序执行、接口响应、批处理效率更高,必须使用并发编程。 4、并发编程是中高级程序员的标配,是拿高薪的必备条件。 【优惠说明】 1、120余节视频课,原价299元,今日报名立减100,仅需199元 2、现在购课,就送价值800元的编程大礼包! 备注:请添加微信:itxy41,按提示获取讲师答疑服务。 【主讲讲师】 尹洪亮Kevin: 现任职某互联网公司首席架构师,负责系统架构、项目群管理、产品研发工作。 10余年软件行业经验,具有数百个线上项目实战经验。 擅长JAVA技术栈、高并发高可用伸缩式微服务架构、DevOps。 主导研发的蜂巢微服务架构已经成功支撑数百个微服务稳定运行 【推荐你学习这门课的理由:知识体系完整+丰富学习资料】 1、 本课程总计122课时,由五大体系组成,目的是让你一次性搞定并发编程。分别是并发编程基础、进阶、精通篇、Disruptor高并发框架、RateLimiter高并发访问限流吗,BAT员工也在学。 2、课程附带附带3个项目源码,几百个课程示例,5个高清PDF课件。 3、本课程0基础入门,从进程、线程、JVM开始讲起,每一个章节只专注于一个知识点,每个章节均有代码实例。 【课程分为基础篇、进阶篇、高级篇】 一、基础基础篇从进程与线程、内存、CPU时间片轮训讲起,包含线程的3种创建方法、可视化观察线程、join、sleep、yield、interrupt,Synchronized、重入、对象、类、wait、notify、线程上下文切换、守护线程、阻塞式安全队列等内容。 二、进阶篇 进阶篇课程涵盖volatied关键字、Actomic类、可见性、原子性、ThreadLocal、Unsafe底层、同步类容器、并发类容器、5种并发队列、COW容器、InheritableThreadLocal源码解析等内容。 三、精通篇 精通篇课程涵盖JUC下的核心工具类,CountDownLath、CyclicBarrier、Phaser、Semaphore、Exchanger、ReentrantLock、ReentrantReadWriteLock、StampedLock、LockSupport、AQS底层、悲观、乐观、自旋、公平、非公平、排它、共享、重入、线程池、CachedThreadPool、FixedThreadPool、ScheduledThreadPool、SingleThreadExecutor、自定义线程池、ThreadFactory、线程池切面编程、线程池动态管理等内容,高并发设计模式,Future模式、Master Worker模式、CompletionService、ForkJoin等 课程中还包含 Disruptor高并发框架讲解:Disruptor支持每秒600万订单处理的恐怖能力。深入到底层原理和开发模式,让你又懂又会用。 高并发访问限流讲解:涵盖木桶算法、令牌桶算法、Google RateLimiter限流开发、Apache JMeter压力测试实战。 【学完后我将达到什么水平?】 1、 吊打一切并发编程相关的笔试题、面试题。 2、 重构自己并发编程的体系知识,不再谈并发色变。 3、 精准掌握JAVA各种并发工具类、方法、关键字的原理和使用。 4、 轻松上手写出更高效、更优雅的并发程序,在工作中能够提出更多的解决方案。 【面向人群】 1、 总感觉并发编程很难、很复杂、不敢学习的人群。 2、 准备跳槽、找工作、拿高薪的程序员。 3、 希望提高自己的编程能力,开发出更高效、性能更强劲系统的人群。 4、 想要快速、系统化、精准掌握并发编程的人群。 【课程知识体系图】
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值