线程Lock

举报
yd_57386892 发表于 2021/04/25 00:01:03 2021/04/25
【摘要】 我们之前学习了synchronized,今天来介绍一下lock。lock与synchronized一样都是为了多线程在竞争公共资源时,能不发生冲突,就是一个线程获取了锁,就去执行代码块,其它线程只能等待第一个线程执行完同步代码块,才能有机会获取到synchronized锁对象。   lock与synchronized最大的区别是,lock锁的释放需要程序员手动调用...

我们之前学习了synchronized,今天来介绍一下lock。lock与synchronized一样都是为了多线程在竞争公共资源时,能不发生冲突,就是一个线程获取了锁,就去执行代码块,其它线程只能等待第一个线程执行完同步代码块,才能有机会获取到synchronized锁对象。

  lock与synchronized最大的区别是,lock锁的释放需要程序员手动调用unlock,一般放在要同步的代码的最后调用unlock,或者try..catch..finally中的finally里调用unlock。当然,从lock释放锁的灵活性上来说,lock的性能更高些,因为synchronized必须等待代码块整个执行完毕才能自动释放锁,而unlock可由程序员手动释放,随时释放,只要不影响多线程同步。

synchronized与lock的示例代码如下:

 


  
  1. package cn.itcast.heima2;
  2. import java.util.concurrent.locks.Lock;
  3. import java.util.concurrent.locks.ReentrantLock;
  4. public class LockTest {
  5. /**
  6. * @param args
  7. */
  8. public static void main(String[] args) {
  9. new LockTest().init();
  10. }
  11. private void init(){
  12. final Outputer outputer = new Outputer();
  13. new Thread(new Runnable(){
  14. @Override
  15. public void run() {
  16. while(true){
  17. try {
  18. Thread.sleep(10);
  19. } catch (InterruptedException e) {
  20. // TODO Auto-generated catch block
  21. e.printStackTrace();
  22. }
  23. outputer.output("gaoxiaowei");
  24. }
  25. }
  26. }).start();
  27. new Thread(new Runnable(){
  28. @Override
  29. public void run() {
  30. while(true){
  31. try {
  32. Thread.sleep(10);
  33. } catch (InterruptedException e) {
  34. // TODO Auto-generated catch block
  35. e.printStackTrace();
  36. }
  37. outputer.output("liudehua");
  38. }
  39. }
  40. }).start();
  41. }
  42. static class Outputer{
  43. Lock lock = new ReentrantLock();
  44. public void output(String name){
  45. int len = name.length();
  46. lock.lock();
  47. try{
  48. for(int i=0;i<len;i++){
  49. System.out.print(name.charAt(i));
  50. }
  51. System.out.println();
  52. }finally{
  53. lock.unlock();
  54. }
  55. }
  56. public synchronized void output2(String name){
  57. int len = name.length();
  58. for(int i=0;i<len;i++){
  59. System.out.print(name.charAt(i));
  60. }
  61. System.out.println();
  62. }
  63. public static synchronized void output3(String name){
  64. int len = name.length();
  65. for(int i=0;i<len;i++){
  66. System.out.print(name.charAt(i));
  67. }
  68. System.out.println();
  69. }
  70. }
  71. }

其中output函数使用了lock,于是两个thread不断输出字符串“gaoxiaowei”,“liudehua”,就不会乱,不会出现类似于这样的输出:"gaoxliudehuaiaowei"

其中output2函数使用了synchronized ,它也可以达到多线程同步的效果。

           值得注意的是如果 生成两个Outputer对象就不行了,例如再创建一个Outputer对象,    final Outputer outputer2 = new Outputer();  然后让输出liudehua的线程(第2个new Thread) 使用outputer2.output照样会乱,例如类似于这样的输出:"gaoxliudehuaiaowei"。这是因为synchronized或lock,创建的锁对象就是output对象。多线程调用同一Outputer 对象的output函数可以达到同效果,但是当一个线程使用output对象,第二个线程使用output2对象,那么这两个线程在调用output.output()函数与output2.output()函数时,是不会同步的,因为它们分别持有的锁是output.this 与 output2.this,是两把不同的锁,各自玩各自的,互相不受影响,都无法锁住对方。

 

其中其中output3函数使用了synchronized, output3注意了,是一个静态函数,synchronized关键字对应的锁对象是 Output.class类的字节码,它能锁住所有类对象,这个时候即使创建了inal Outputer outputer2 = new Outputer(); 让线程1调用 outputer.output3(),线程2调用output2.output3(), 是不会出现错乱的,因为outputer与output2都属于Output类型,synchronized关键字对应的锁对象是 Output.class类的字节码,它们在执行output3()函数时,用的是同一把锁:Output.class。因此最终还是可以达到多个线程同步输出字符串到屏幕设备的。

 

但是,无论是synchronized,还是我们上述讲的lock, 性能都很差,因为它们的锁有些盲目,比如当2个线程都是读数据,并没有去写数据,所以不会出现多线程读取多乱问题。这个时候synchronized和lock就有点死板了,当第1个线程读取变量值(或数据)的时候,线程2也想读,但是必须得等线程1把锁释放了才行,即使线程2不是来捣乱的。

要改善读-读性能问题,需要使用ReentrantReadWriteLock(读写锁)来分别创建读锁 和 写锁。读锁就能解决上述问题,让读--读自由。

 

文章来源: blog.csdn.net,作者:冉航--小虾米,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/gaoxiaoweiandy/article/details/116096384

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。