`
suhuanzheng7784877
  • 浏览: 701354 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
Ff8d036b-05a9-33b5-828a-2633bb68b7e6
读金庸故事,品程序人生
浏览量:47681
社区版块
存档分类
最新评论

Java分布式应用学习笔记06浅谈并发加锁机制分析

阅读更多

1.  前言

之前总结的多线程的调度、并发调度、线程加锁安全等等并发包底层大都使用了线程锁机制。咱们通过锁的源码来看看JDK如何将这些资源进行加锁限制的,怎么就能做到线程集中等待后就唤醒主线程的。

2.  一段并发包源码

以下是java.util.concurrent.CyclicBarrier的底层代码片段。

    private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            ……………………省略
        } finally {
            lock.unlock();
        }
    }

 

在执行等待的时候,里面使用了ReentrantLock对其进行资源加锁,保证在代码块中使用变量、读写变量不会被别的线程打扰。

3.  轻量级锁ReentrantLock

基于以上程序我们就来看看ReentrantLock内部是如何工作的。ReentrantLock内部有个Sync类,继承自AbstractQueuedSynchronizer,基于Sync又有2个子类继承于它,而ReentrantLock就是依靠这2Sync子类为内核实现的。代码大家直接看JDK源程序即可。

ReentrantLocklock()方法,它的加锁方法实际上是使用的内部静态类Sync的方法,至于调用的是公平——FairSync还是不公平的——NonfairSync,这个要看构建ReentrantLock的时候的构造函数了。

NonfairSync的加锁方法实现流程是这样的:首先基于CAS——Compare and Swap原则,先将state0尝试变成1。如果设置成功了,证明了一个事实——此时此刻,没有其他的线程持有该锁。则当前线程设置为ExclusiveOwnerThread(独家拥有线程);那么如果状态变量state设置不成功呢,则又揭示了一个事实,当前线程锁已经被其他线程所持有,那么调用acquire方法,该方法首先先尝试再次获取状态state,如果为0了,那么继续尝试设置状态为1。若成功则与此时无其他线程持有锁操作雷同。如果state依然不为0,则判断当前线程是否为独家拥有线程变量——exclusiveOwnerThread,是的话将state的值+1.如果不是,则将当前线程放入等待队列中挂起,挂起方法

    public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        unsafe.park(false, 0L);
        setBlocker(t, null);
    }

 

FairSynclock()方法和NonfairSync大同小异。只不过它没有获取state变量信息的过程,直接是调用acquire(1)方法请求线程锁。

ReentrantLockunlock()方法,解锁的方法比较简单,不区分公平与不公平,都是获取当前state值,之后减去释放锁的个数,减操作后结果如果为0,表示锁可以释放了。通知队列上的那些线程,唤醒队列头线程,进行run操作。

这些加锁、解锁操作很明显都离不开队列——AbstractQueuedSynchronizer的辅助操作,将线程组织成为线程队列形式。

4.  读写锁ReentrantReadWriteLock

了解了ReentrantLock在加锁原理上使用了一把锁,一把钥匙开一把锁嘛~而如果遇到大部分操作是读操作的、而写操作比较少的时候使用ReentrantLock未免有点“奢侈”。使用ReentrantReadWriteLock——读写双锁进行读取和写入,在读多写少的场景下可以提升不少性能。它的基本工作原理是这样的:当使用读锁进行lock的时候,就算是有其他线程也进行读操作,而不是写操作的时候,线程不会阻塞,可以并行执行,和没有加lock几乎是一样的。当调用写锁的lock方法时,无论其他线程是什么性质的(读、写),都阻塞,所以这个双重锁适用于读操作频率较多、写操作频率较少的操作。咱们看个使用例子

	// 读写锁
	static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();

			// 获得读锁-加锁
			reentrantReadWriteLock.readLock().lock();
			String str = listString.get(sum);
			reentrantReadWriteLock.readLock().unlock();

			// 获得写锁-加锁
			reentrantReadWriteLock.writeLock().lock();
			String str = Thread.currentThread().getName() + "--write:" + sum;
			listString.add(str);
			reentrantReadWriteLock.writeLock().unlock();

 因为一些特殊原因,不能将源码完整的场景全部给出,只能写出简单的使用关键的片段。

读锁的加锁源代码片段是

    public final void acquireShared(int arg) {
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
    }

 

写锁的加锁源码片段是

    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

 

相比较而言,就是上面说过的一旦写锁加锁时发现有其他线程进行了操作,则将当前线程放置于线程等待队列中——之后再唤醒。而读操作锁直接进行了共享线程,并发读取。

5.  总结

综合前面几篇线程调度、多线程并发计算等等,底层都是基于加锁、抽象线程等待队列AbstractQueuedSynchronizer及其2个具体子类、CAS算法的综合体现。使用多线程并发包后我们可以构建高可用和高计算能力的分布式系统。

注意:如果没有将解锁代码写到finally块中,是有问题的!!如果发生了任何的运行时异常,会向上抛,那么锁会永远不会解除,那么造成的后果大家一定知道了。

31
5
分享到:
评论
20 楼 maketuwen198501 2011-08-27  
不错不错。
19 楼 hufei023090 2011-08-22  
恩,学习了啊
18 楼 suhuanzheng7784877 2011-08-22  
tan4836128 写道
有收获,顶楼主

献丑献丑,见笑见笑,可惜不适合你暴力的口味哈
17 楼 tan4836128 2011-08-22  
有收获,顶楼主
16 楼 你若无情我便休 2011-08-22  
3q.....
15 楼 suhuanzheng7784877 2011-08-22  
引用
我错了,在公司这样说话习惯了

不过的确一直觉得用java做中央控制不靠谱,所以如果不是中央控制,多台机器的同步是依赖分布式缓存的

而且概念上来说,分布式是指多台机器,而java的并发包是工作于本虚拟机内存的,两者其实是没有关系的

不知我说的有没有一丁点道理呢??呵呵

是是是,交流,互相学习才是最大的目的。我一直再提起你的一些良言,很中肯,对于我也是好的提醒与鞭策。snake1987不必太过认真~~
14 楼 snake1987 2011-08-22  
thomas_mule0086 写道
snake1987 写道
被分布式诱惑进来的~
建议改下题目~~
实际分布式跟java的并发包没有一毛钱的关系~

你没在构建分布式系统中用到这些并发技术,不代表别人没用过,小盆友,谦虚点。


我错了,在公司这样说话习惯了

不过的确一直觉得用java做中央控制不靠谱,所以如果不是中央控制,多台机器的同步是依赖分布式缓存的

而且概念上来说,分布式是指多台机器,而java的并发包是工作于本虚拟机内存的,两者其实是没有关系的

不知我说的有没有一丁点道理呢??呵呵

13 楼 suhuanzheng7784877 2011-08-22  
jilen 写道
并发就并发,不一定非要套个分布式吧

是是是,标题有点不太合适,这个笔者承认。呵呵
12 楼 suhuanzheng7784877 2011-08-22  
引用
你没在构建分布式系统中用到这些并发技术,不代表别人没用过,小盆友,谦虚点。

朋友,别那么火药味十足吧。
11 楼 suhuanzheng7784877 2011-08-22  
snake1987 写道
被分布式诱惑进来的~
建议改下题目~~
实际分布式跟java的并发包没有一毛钱的关系~

有些场景是在集群系统中做节点资源调度,处理不同节点、不同客户端、不同终端的时候并发的情况确实有关系的。
10 楼 suhuanzheng7784877 2011-08-22  
引用
搜狐畅游招聘Java开发工程师啦~!~!

这个得去招聘版块吧~~~
9 楼 suhuanzheng7784877 2011-08-22  
你若无情我便休 写道
问一下lz,这个东西和用synchronized有什么区别吗?

ReentrantLock提供了可轮询的锁请求,他可以尝试的去取得锁,如果取得成功则继续处理,取得不成功,可以等下次运行的时候处理,所以不容易产生死锁,而synchronized则一旦进入锁请求要么成功,要么一直阻塞。
synchronized块结束,或者修饰的方法结束后自动释放锁。

以下是别人的一段话:我觉得比较清晰了

http://zzhonghe.iteye.com/blog/826162

synchronized:
在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronize,另外可读性非常好,不管用没用过5.0多线程包的程序员都能理解。

ReentrantLock:
ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。

这个回头咱们可以写一段程序一个用synchronized,一个用ReentrantLock作时间和内存上的测试

8 楼 你若无情我便休 2011-08-21  
问一下lz,这个东西和用synchronized有什么区别吗?
7 楼 OLIVER_kahn111 2011-08-21  
说实话,没看懂,凑凑人气
6 楼 thomas_mule0086 2011-08-20  
snake1987 写道
被分布式诱惑进来的~
建议改下题目~~
实际分布式跟java的并发包没有一毛钱的关系~

你没在构建分布式系统中用到这些并发技术,不代表别人没用过,小盆友,谦虚点。
5 楼 jilen 2011-08-20  
并发就并发,不一定非要套个分布式吧
4 楼 struts23045 2011-08-20  
引用
工作地点:北京

可惜不在北京,催悲了。
3 楼 季铵盐 2011-08-20  
2 楼 snake1987 2011-08-20  
被分布式诱惑进来的~
建议改下题目~~
实际分布式跟java的并发包没有一毛钱的关系~
1 楼 uuid198909 2011-08-19  
终于等到了~

相关推荐

    Java分布式应用学习笔记

    Java分布式应用学习笔记 在Java世界中,分布式应用是指由多个独立组件通过网络通信协同工作的系统。这种架构模式常用于构建大规模、高可用性、可扩展的系统。本笔记将深入探讨Java分布式应用的核心概念、技术和实践...

    Java分布式应用学习笔记01分布式Java应用和SOA

    ### Java分布式应用与SOA概览 在深入探讨Java分布式应用和面向服务架构(SOA)之前,我们首先需要理解这两个概念的基本含义及其在现代IT系统中的重要性。 #### Java分布式应用 Java分布式应用是指利用Java编程...

    Java分布式应用学习笔记-谈JVM.doc

    【Java分布式应用学习笔记-谈JVM】 在Java分布式应用中,JVM(Java虚拟机)扮演着至关重要的角色。虽然有些人可能认为分布式系统与JVM的关系并不密切,但事实上,尤其是在大型分布式环境,如云计算服务平台,对Java...

    Java分布式应用学习笔记07线程池应用

    ### Java分布式应用学习笔记07线程池应用 在深入探讨Java分布式应用中线程池的应用之前,我们先来理解一下线程池的基本概念及其在并发编程中的重要性。线程池是Java并发编程的核心技术之一,它通过复用一组预创建的...

    Java【分布式】学习笔记01分布式Java应用

    从给定的文件信息来看,标题和描述都指向了“Java分布式学习笔记01分布式Java应用”,这显然是关于Java在分布式环境下的应用和技术的学习资料。虽然提供的部分内容由于格式问题难以直接解析,但我们可以根据标题、...

    java分布式应用学习笔记05多线程下的并发同步器.pdf

    本篇笔记将深入探讨Java中的并发同步机制,包括核心概念、工具类以及在实际开发中的应用。 首先,我们要理解什么是线程安全。线程安全是指在多线程环境下,一个方法或类能够正确处理多个线程同时访问的情况,不会...

    Java分布式应用学习笔记03JVM对线程的资源同步和交互机制

    ### Java分布式应用学习笔记03:JVM对线程的资源同步和交互机制 在深入探讨Java虚拟机(JVM)如何处理线程间的资源同步与交互机制之前,我们先来明确几个关键概念:线程、多线程、同步、并发以及它们在Java中的实现...

    Java 分布式应用程序设计代码

    Java分布式应用程序设计是一种构建大型、可扩展且高可用性系统的方法。在Java中,通过利用网络中的多台计算机,可以创建能够跨越多个节点共享资源、处理任务和存储数据的复杂应用。这种技术允许应用程序的不同部分在...

    Java 分布式应用程序设计

    Java 分布式应用程序设计是构建大型、可扩展和高...以上只是Java分布式应用程序设计的一些核心知识点,实际应用中还会涉及到缓存管理、数据库分库分表、安全认证、限流熔断等多个方面,需要不断学习和实践来提升技能。

    Java分布式应用学习笔记09JMX-MBean的介绍.doc

    java

    java分布式系统架构源码

    Java分布式系统架构是一种将应用程序分布在多个计算节点上运行的技术,以提高系统的可伸缩性、容错性和性能。源码分析对于理解这种架构至关重要,尤其是对于开发者来说,它提供了深入学习和自定义系统的机会。本资源...

    java分布式应用程序设计 pdf+源码

    通过深入学习和实践这些内容,开发者能够掌握Java在分布式系统中的高级应用,提升构建高可用、高性能、可扩展的系统的能力。无论是初学者还是经验丰富的开发者,这份资源都能提供宝贵的参考和指导。

    浅谈分布式事务实现技术及应用场景探讨.pdf

    "浅谈分布式事务实现技术及应用场景探讨" 分布式事务是指在分布式系统中,多个节点之间的数据访问和更新操作集合,需要保证事务的原子性、一致性、隔离性和持久性。随着软件系统支持用户数的不断提高,对其架构的...

    [实战]Java分布式高级架构师课程学习笔记.docx

    【Java分布式高级架构师课程学习笔记】 在Java分布式高级架构师的学习过程中,涵盖了多个关键领域的技术,包括数据库的高可用方案、缓存系统、消息中间件以及分布式协调服务。以下是对这些主题的深入探讨: 1. **...

    java 分布式应用程序设计.rar

    Java分布式应用程序设计是Java开发中的一个重要领域,它涉及到多个计算机节点通过...通过学习和实践这些Java分布式应用程序设计的知识点,开发者可以构建出高效、可扩展且可靠的分布式系统,满足现代企业级应用的需求。

    分布式Java应用基础与实践pdf

    在"分布式Java应用基础与实践"这本书中,读者可以深入学习这些概念,并通过实例学习如何在实际项目中应用。无论是初学者还是经验丰富的开发者,都能从中受益,提升自己的分布式系统设计和开发能力。

Global site tag (gtag.js) - Google Analytics