之前的文章在介绍java 的同步和jmm模型的时候,都介绍了synchronized锁。今天我们呢接着java中的锁,来介绍另一种锁的实现方式lock接口。
lock出现之前的话,Java就是通过synchronized关键字实现的加锁。但是在javase 5之后,并发包中新增了Lock接口用来实现锁的功能。既然新增了lock接口,那么他肯定是和synchronized关键字在实现锁的方式上有区别的。
synchronized:隐式的释放和获取锁,使用起来比较方便,但是缺少了对锁的可操作性,将锁的获取和释放固化了。
lock接口:需要自己手动获取和释放锁,对锁的操作性变强了,而且它可以设置锁的类型(公平锁和非公平锁),但是它也有自己的缺点,那就是不能自动释放锁,如果你忘记释放锁,将会阻塞后续的所有线程。
上面介绍的只是大概的区别,想要细致的了解,两种锁的区别,可以自行去java官网看使用手册。
ReetranLock重入锁,顾名思义就是支持可重入的锁,它锁能够支持一个线程对资源的重复加锁。synchronized也是可重入锁。
重入锁的特点就是当你有了这个锁之后,你再去获取这个锁,不会被阻塞(和加锁一样的道理),这个特性实现需要解决两个问题。
1.锁的再次获取:锁需要去识别获取锁的线程是不是当前占据锁的线程,如果是,则获取成功。
2.锁的最终释放:线程重复n次获取了锁,然后释放了n次锁之后,其他线程可以获取到当前的锁(意味着需要有一个计数器记录获取锁的次数,然后在释放锁的时候,将次数减1,当减到为0的时候,为释放成功)。
ReentranLock是通过组合自定义同步器(之后我们会单独一个章节介绍同步器)实现的。
公平锁:锁的获取按照先到先得的原则,也就是FIFO。
非公平锁:大家一起竞争,谁竞争到就算谁的。
两种锁各有优缺点,非公锁性能会比较好,但是可能会出现有的线程长时间获取不到锁。公平锁性能相对较差,但是不会出现有的线程长时间获取不到锁的情况。所以总的来说,还是非公平锁使用的较多(毕竟性能好)。
上面介绍的锁,都是排他锁,也就是同一时间只有一个线程可以获取到锁,然后对共享资源进行操作。
读写锁(ReentrantReadWriteLock)支持同一时间,多个线程操作共享资源。读写锁又分为读锁和写锁。读锁允许同一时间多个线程对共享资源进行访问,但是写锁就不支持了,写是排他锁,同一时间只能有一个线程对共享资源操作。
读锁和写锁是互斥的,也就是一个共享资源加了写锁之后,其他线程不能获取写锁了,那写锁的线程如果想获取读锁怎么办,可以通过锁降级实现,就是当前线程占有着写锁,然后获取读锁,获取到读锁之后,再释放写锁(一定要是获取到读锁之后再释放写锁,不然再获取到读锁之前,释放写锁,期间有其他线程获取到写锁,修改数据,是对当前线程不可见的)。
今天我们通过介绍另一种锁的实现方式Lock接口,将java中的常见的锁的种类给大家进行了简答的介绍,至于每种锁的具体实现,和底层原理,后续章节将会单独介绍。