JDK 5.0中更机动、更具可伸缩性的锁定机制[Java编程]
本文“JDK 5.0中更机动、更具可伸缩性的锁定机制[Java编程]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:
JDK 5.0为开辟人员开辟高性能的并发利用程序供应了一些很有效的新挑选.比方, java.util.concurrent.lock 中的类 ReentrantLock 被作为 Java 语言中 synchronized 功效的替换,它具有相同的内存语义、相同的锁定,但在争用条件下却有更好的性能,此外,它还有 synchronized 没有供应的其他特点.这能否意味着我们该当忘掉 synchronized ,转而只用 ReentrantLock 呢?并发性专家 Brian Goetz 刚从他的夏日休假中返回,他将为我们供应答案.
多线程和并发性并非什么新内容,但是 Java 语言计划中的创新之一就是,它是第一个直接把跨平台线程模子和正规的内存模子集成到语言中的主流语言.核心类库包含一个 Thread 类,可以用它来构建、启动和操作线程,Java 语言包含了跨线程传达并发性约束的构造 —— synchronized 和 volatile .在简化与平台无关的并发类的开辟的同时,它决没有使并发类的编写工作变得更烦琐,只是使它变得更简单了.
synchronized 快速回想
把代码块声明为 synchronized,有两个重要后果,普通是指该代码具有 原子性(atomicity)和 可见性(visibility).原子性意味着一个线程一次只能履行由一个指定监控对象(lock)保护的代码,从而避免多个线程在更新同享状况时彼此冲突.可见性则更为奇妙;它要对付内存缓存和编译器优化的各种反常行为.普通来说,线程以某种没必要让其他线程立便可以看到的方法(不管这些线程在存放器中、在处理器特定的缓存中,还是通过指令重排大概其他编译器优化),不受缓存变量值的约束,但是假如开辟人员利用了同步,以下面的代码所示,那么运行库将确保某一线程对变量所做的更新先于对现有 synchronized 块所举行的更新,当进入由同一监控器(lock)保护的另一个 synchronized 块时,将立即可以看到这些对变量所做的更新.近似的法则也存在于 volatile 变量上.(有关同步和 Java 内存模子的内容,请参阅 参考资料.)
synchronized (lockObject) {
// update object state
}
所以,实现同步操作需求考虑安全更新多个同享变量所需的一切,不能有争用条件,不能破坏数据(假定同步的边界位置精确),并且要保证精确同步的其他线程可以看到这些变量的最新值.通过定义一个清楚的、跨平台的内存模子(该模子在 JDK 5.0 中做了改正,改正了本来定义中的某些错误),通过服从下面这个简单法则,构建“一次编写,到处运行”的并发类是有大概的:
不管什么时刻,只要您将编写的变量接下来大概被另一个线程读取,大概您将读取的变量最后是被另一个线程写入的,那么您必须举行同步.
不过目前好了一点,在近来的 JVM 中,没有争用的同步(一个线程拥有锁的时刻,没有其他线程计划得到锁)的性能本钱还是很低的.(也不老是这样;早期 JVM 中的同步还没有优化,所以让很多人都这样认为,但是目前这变成了一种曲解,人们认为不管是不是争用,同步都有很高的性能本钱.)
对 synchronized 的改良
如此看来同步相当好了,是么?那么为什么 JSR 166 小组花了这么多时间来开辟 java.util.concurrent.lock 框架呢?答案很简单-同步是不错,但它并不完善.它有一些功效性的限制 —— 它无法中止一个正在等候得到锁的线程,也无法通过投票得到锁,假如不想等下去,也就没法得到锁.同步还要求锁的释放只能在与得到锁所在的仓库帧相同的仓库帧中举行,大都情形下,这没问题(并且与非常处理交互得很好),但是,确切存在一些非块构造的锁定更符合的情形.
ReentrantLock 类
java.util.concurrent.lock 中的 Lock 框架是锁定的一个抽象,它答应把锁定的实现作为 Java 类,而不是作为语言的特点来实现.这就为 Lock 的多种实现留下了空间,各种实现大概有差别的调度算法、性能特点大概锁定语义. ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义,但是增添了近似锁投票、按时锁等候和可中止锁等候的一些特点.此外,它还供应了在激烈争用情形下更佳的性能.(换句话说,当很多线程都想拜候同享资源时,JVM 可以花更少的时刻来调度线程,把更多时间用在履行线程上.)
reentrant 锁意味着什么呢?简单来说,它有一个与锁相关的获得计数器,假如拥有锁的某个线程再次得到锁,那么获得计数器就加1,然后锁需求被释放两次才能得到真正释放.这模拟了 synchronized 的语义;假如线程进入由线程已经拥有的监控器保护的 synchronized 块,就答应线程持续举行,当线程退出第二个(大概后续) synchronized 块的时刻,不释放锁,只有线程退出它进入的监控器保护的第一个 synchronized 块时,才释放锁.
在查看清单 1 中的代码示例时,可以看到 Lock 和 synchronized 有一点明显的辨别 —— lock 必须在 finally 块中释放.不然,假如受保护的代码将抛出非常,锁就有大概永久得不到释放!这一点辨别看起来大概没什么,但是实际上,它极其重要.忘掉在 finally 块中释放锁,大概会在程序中留下一个按时炸弹,当有一天炸弹爆炸时,您要耗费很大力气才有找到源头在哪.而利用同步,JVM 将确保锁会得到自动释放.
以上是“JDK 5.0中更机动、更具可伸缩性的锁定机制[Java编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
本文地址: | 与您的QQ/BBS好友分享! |