慢谈JAVA锁机制

作为一个普通的java开发者来讲,多线程中有两种常用的方法来锁,一种是同步方法,另一种是同步代码块,这个是在JVM层面来实现的,它实现的原理是每个对象有一个记数器,每有一个线程来执行这个临界区(共享资源)时,记数器加1,如果执行完后,将记数器减1。这个对象相当于一个公共的监视器,判断现在有多少个线程在阻塞(等待),所有的线程都可以看见,以此作为标志来判断是否可以可以获取进入临界区的权限。大概实现这个需求,需要完成以下几个方面内容:
1.能否进入临界区(每次只有一个),也即获得进入临界区的许可证没?
2.等待队列(阻塞,即等待的线程需要在一个公共地方存储下来);
3.如何从等待队列中选择其中的一个线程来调度执行(涉及公共与否)

假设临界区的许可证初始值(permit)为1(表示只能有一个线程能进入)-----&gt所有的线程都能看到这个值
       等待队列list,加入的次序是进入队列的次序。

一个线程来到,如果是第一个线程来获取这个permit,发现可用,就进入临界区,同时将permit减1,为0;
其它的线程来到,发现permit值为0,必须等待,进入队列list
加了N个线程到List中去;
第一个线程执行完后,将permit加1,
调度程序从list中选取一个来调度执行。

以上只是从实现这个功能的需求上去考虑,底层的实现如何我们现在还不得而知。而在JDK源码中有一个并发框架,它里面提供了好多工具类,我们可以分析它的实现原理。它里面有几个大的类:
1.并发集合框架,如ConcurrentHashMap,引入Segment的概念来实现并发的;
2.信号量:与上面的实现过程差不多;
3.锁,这个还分为Reentrantlock,ReentrantReadWriterLock。
  Reentrant翻译成中文是可重入的意思,也即是一个线程获取锁后,在里面还可以获取锁,这个是可避免死锁的,否则现在已经占用,还在申请中,那不死锁还是什么呢?
  锁通常还与条件锁一起使用,这是为什么呢?相当于锁的嵌套,其实这里有两层原因,一是临界区可以由不同类型的线程进入(生产者与消费者),如果生产者进入,但是现在没有存储空间了,那么它只能等待了,尽管它能进入,但现在还是不能干活的,必须阻塞;另一个原因,需要通过这个条件锁的signal方法来唤醒等待的线程。
4.同步的工具:如CountDownLatch

上面有一个公共的父类:AQS,它里有有一个等待队列(由双向链表组成的,毕竟你不知道有多少个线程需要进入,所以还是由链表来实现比较好),它里面有一个state表示监视器,也可以看作是许可证(permit),如果是锁的话,它默认为0,如果是信号量就是new时指定的permit值。
对于锁和信号量,它对state的使用是不同的:
锁:初始值为0
       大于0,其它线程需要等待
       lock(),state加1;unlock(),state减1.

信号量:初始值就是指定的permit(permit值赋给了state)
      大于0,其它线程有能力进入临界区
      小于0,其它线程需要等待。
      acquire(),state减1,release(),state加1

对于其它所有的线程都可见,state设置成 volatile.

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30024515/viewspace-1433778/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/30024515/viewspace-1433778/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值