Java多线程之内置锁与显示锁

Java中具有通过Synchronized实现的内置锁,和ReentrantLock实现的显示锁,这两种锁各有各的好处,算是互有补充,今天就来做一个总结。

Synchronized

内置锁获得锁和释放锁是隐式的,进入synchronized修饰的代码就获得锁,走出相应的代码就释放锁。

Java多线程之内置锁与显示锁

Java学习交流群:495273252

通信

与Synchronized配套使用的通信方法通常有wait(),notify()。

wait()方法会立即释放当前锁,并进入等待状态,等待到相应的notify并重新获得锁过后才能继续执行;

notify()不会立刻立刻释放锁,必须要等notify()所在线程执行完synchronized块中的所有代码才会释放。用如下代码来进行验证:

Java多线程之内置锁与显示锁

Java多线程之内置锁与显示锁

Java学习交流群:495273252

运行结果

Java多线程之内置锁与显示锁

Java学习交流群:495273252

可见读线程开始运行,开始wait过后,写线程才获得锁;写线程走出同步块而不是notify过后,读线程才wait结束,亦即获得锁。所以notify不会释放锁,wait会释放锁。值得一提的是,notifyall()会通知等待队列中的所有线程。

编码

编码模式比较简单,单一,不必显示的获得锁,释放锁,能降低因粗心忘记释放锁的错误。使用模式如下:

Java多线程之内置锁与显示锁

Java学习交流群:495273252

灵活性

  • 内置锁在进入同步块时,采取的是无限等待的策略,一旦开始等待,就既不能中断也不能取消,容易产生饥饿与死锁的问题

  • 在线程调用notify方法时,会随机选择相应对象的等待队列的一个线程将其唤醒,而不是按照FIFO的方式,如果有强烈的公平性要求,比如FIFO就无法满足

性能

Synchronized在JDK1.5及之前性能(主要指吞吐率)比较差,扩展性也不如ReentrantLock。但是JDK1.6以后,修改了管理内置锁的算法,使得Synchronized和标准的ReentrantLock性能差别不大。

ReentrantLock

ReentrantLock是显示锁,需要显示进行 lock 以及 unlock 操作。

通信

与ReentrantLock搭配的通行方式是Condition,如下:

Java多线程之内置锁与显示锁

Java学习交流群:495273252

Condition是被绑定到Lock上的,必须使用lock.newCondition()才能创建一个Condition。从上面的代码可以看出,Synchronized能实现的通信方式,Condition都可以实现,功能类似的代码写在同一行中。而Condition的优秀之处在于它可以为多个线程间建立不同的Condition,比如对象的读/写Condition,队列的空/满Condition,在JDK源码中的ArrayBlockingQueue中就使用了这个特性:

Java多线程之内置锁与显示锁

Java多线程之内置锁与显示锁

Java多线程之内置锁与显示锁

Java学习交流群:495273252

编码

Java多线程之内置锁与显示锁

Java学习交流群:495273252

相比于Synchronized要复杂一些,而且一定要记得在finally中释放锁而不是其他地方,这样才能保证即使出了异常也能释放锁。

灵活性

  • lock.lockInterruptibly() 可以使得线程在等待锁支持响应中断;lock.tryLock() 可以使得线程在等待一段时间过后如果还未获得锁就停止等待而非一直等待。有了这两种机制就可以更好的制定获得锁的重试机制,而非盲目一直等待,可以更好的避免饥饿和死锁问题

  • ReentrantLock可以成为公平锁(非默认的),所谓公平锁就是锁的等待队列的FIFO,不过公平锁会带来性能消耗,如果不是必须的不建议使用。这和CPU对指令进行重排序的理由是相似的,如果强行的按照代码的书写顺序来执行指令,就会浪费许多时钟周期,达不到最大利用率

性能

虽然Synchronized和标准的ReentrantLock性能差别不大,但是ReentrantLock还提供了一种非互斥的读写锁,

也就是不强制每次最多只有一个线程能持有锁,它会避免“读/写”冲突,“写/写”冲突,但是不会排除“读/读”冲突,

因为“读/读”并不影响数据的完整性,所以可以多个读线程同时持有锁,这样在读写比较高的情况下,性能会有很大的提升。

下面用两种锁分别实现的线程安全的linkedlist:

Java多线程之内置锁与显示锁

Java多线程之内置锁与显示锁

Java学习交流群:495273252

读写锁测试代码:

Java多线程之内置锁与显示锁

Java多线程之内置锁与显示锁

Java学习交流群:495273252

同步锁测试代码:

Java多线程之内置锁与显示锁

Java多线程之内置锁与显示锁

Java学习交流群:495273252

结果:

Java多线程之内置锁与显示锁

Java学习交流群:495273252

可见读写锁的确是优于纯碎的互斥锁

总结

内置锁最大优点是简洁易用,显示锁最大优点是功能丰富,所以能用内置锁就用内置锁,在内置锁功能不能满足之时在考虑显示锁。

关于两种锁,目前接触到的就是这么多,总结不到位之处,欢迎拍砖。

学习Java的同学注意了!!!

学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群495273252,我们一起学Java!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然可以!下面是一篇关于Java多线程中的""的博客: ## Java多线程中的Java多线程编程中,是一种重要的同步机制,用于保护共享资源的访问。使用可以防止多个线程同时对共享资源进行修改,从而避免数据不一致的问题。 ### 1. 什么是是一种同步机制,它可以让多个线程按照一定的顺序访问共享资源。在Java中,可以是隐式的,也可以是显式的。 - 隐式:通过关键字`synchronized`来实现,它可以用于修饰方法或代码块。当一个线程进入被`synchronized`修饰的方法或代码块时,它会自动获取,并在执行完毕后释放。 - 显式:通过`java.util.concurrent.locks`包中的Lock接口及其实现类来实现,如ReentrantLock。显式需要手动获取和释放,在使用上更加灵活。 ### 2. 的作用 的主要作用是保护共享资源的访问,它可以解决多线程并发访问时可能引发的以下问题: - 竞态条件(Race Condition):当多个线程同时访问共享资源,并且对其进行写操作时,可能会导致数据的不一致。 - 临界区(Critical Section):当多个线程同时访问共享资源,并且对其进行读写操作时,可能会导致数据的不一致。 - 死(Deadlock):当多个线程相互等待对方释放时,可能会导致程序无法继续执行。 ### 3. 的类型 Java中常用的类型包括: - 内置(Intrinsic Lock):也称为监视器(Monitor Lock),是由关键字`synchronized`来实现的。内置是基于对象的,每个对象都有一个用于同步的内置,当一个线程获取了该后,其他线程必须等待。 - 重入(Reentrant Lock):是`java.util.concurrent.locks`包中的一个显式实现类,它具有与内置类似的功能,但提供了更高级的特性,如可重入、公平和超时等。 - 读写(Read-Write Lock):也是`java.util.concurrent.locks`包中的一个显式实现类,它区分了读操作和写操作,允许多个线程同时读取共享资源,但只允许一个线程进行写操作。 ### 4. 的使用示例 下面是一个使用内置`synchronized`来实现线程安全的示例: ```java public class Counter { private int count = 0; public synchronized void increment() { count++; } public synchronized int getCount() { return count; } } ``` 在上述示例中,`increment()`和`getCount()`方法都被`synchronized`修饰,这意味着同一时间只能有一个线程执行这些方法,从而保证了`count`变量的访问安全。 ### 5. 的注意事项 在使用时,需要注意以下事项: - 避免死:在获取的时候,要确保能够及时释放,避免多个线程相互等待对方释放而导致死。 - 避免饥饿:要确保所有线程都有公平获取的机会,避免某个线程一直无法获得而导致饥饿。 - 的粒度:要选择合适的粒度,尽量减小的范围,以提高程序的并发性能。 - 的性能:显式相对于内置,通常具有更高的性能,但使用不当可能导致性能问题。要根据实际情况选择合适的。 ### 总结 Java多线程编程中重要的同步机制,用于保护共享资源的访问。它可以解决竞态条件、临界区和死等问题。在使用时,需要注意避免死和饥饿,选择合适的粒度和类型,以及权衡的性能。 希望本篇博客对你有所帮助!如有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值