- 浏览: 478656 次
- 性别:
- 来自: 大连
文章分类
最新评论
-
龘龘龘:
TrueBrian 写道有个问题,Sample 1中,为了控制 ...
What's New on Java 7 Phaser -
龘龘龘:
楼主总结的不错。
What's New on Java 7 Phaser -
TrueBrian:
有个问题,Sample 1中,为了控制线程的启动时机,博主实际 ...
What's New on Java 7 Phaser -
liguanqun811:
不知道楼主是否对zookeeper实现的分布式锁进行过性能测试 ...
Distributed Lock -
hobitton:
mysql的get lock有版本限制,否则get lock可 ...
Distributed Lock
本文节选自 Effective Java by Joshua Bloch 和 Concurrent Programming in Java by Doug Lea.
1.6 避免过多的同步
1.6.1是否需要同步
过多的同步可能会导致性能降低、死锁,甚至不确定行为。通常,在同步区域内应该做尽可能少的工作。同步区域之外被调用的外来方法被称为“开放调用(open call)”。除了可以避免死锁之外,开放调用还可以极大地增加并发性。
考虑StringBuffer类和BufferedInputStream类,这些类都是线程安全(thread-safe)的,但是它们往往被用于单个线程中,所以它们所做的锁操作往往是不必要的,虽然同步的开销自java平台早期开始就一直在下降,但是它永远也不会消失。一个给定的类是否应该执行内部同步并不总是很清楚,下面是一些指导性的原则。
如果你正在编写的类主要被用于同步环境中,同时也被用于不要求同步的环境中,那么一个合理的方法是,同时提供同步版本和和未同步版本。这也正是Collections Framework采用的方法。还有,java.util.Random也是采用这一种做法是提供一个包装类(wrapper class),它实现一个描述该类的接口,同时在将方法调用转发给内部对象中对应的方法之前执行适当的同步操作。种方法。第二种方法适用于那些不是被设计用来扩展或者重新实现的类,它提供一个未同步的类和一个子类,在子类中包含一些被同步的方法,它们依次调用到超类中对应的方法上。
关于是否对一个用于存取成员变量的方法进行同步,需要考虑两点:合法性和陈旧性。如果成员变量不总是合法的,那么可以的选择是:
- 同步所有存取方法
- 确保用户在得到非法值的时候能得到通知
- 省略存取方法。在并发程序中,对象的属性可以被异步修改,客户通过某行代码得到的值可能在下一行代码中就改变了。因此需要仔细评估存取方法存在的必要性。
如果成员变量的值总是合法的,但是不能是陈旧数据,那么可以的选择是:
- 把成员变量定义为volatile,并去掉存取方法的同步。
1.6.2 分解同步和分解锁
另外一种增加程序并发性的方法是分解同步,如果一个类的行为可以分解为互相独立、互不干扰或者不冲突的子部分,那么就值得用细粒度的辅助对象来重新构造类。普遍的原则是,把类的内部同步操作分得越细,在大多数情况下,它的活性就越高。但是这一点是以更加复杂和潜在的错误为代价的。例如:
public class Shape { public synchronized vodi adjustLocation(){ /*Long time operation*/ } public synchronized vodi adjustDimensions(){ /*Long time operation*/ } }
我们假设adjustLocation不处理维度信息,adjustDimensions不处理位置信息,那么可以考虑把维度和位置信息分解到两个类中, 例如:
public class Shape { private final Location location = new Location(); private final Dimensions dimensions = new Dimensions(); public void adjustLocation(){ location.adjustLocation(); } public void adjustDimensions(){ dimensions.adjustDimensions(); } } public class Location { public synchronized void adjustLocation(){ /*Long time operation*/ } } public class Dimensions { public synchronized void adjustDimensions(){ /*Long time operation*/ } }
如果你不能或者不想分解类,则可以分解每个子功能相关的同步锁。例如
public class Shape { private final Object locationLock = new Object(); private final Object dimensionsLock = new Object(); public void adjustLocation() { synchronized(locationLock) { /*Long time operation*/ } } public void adjustDimensions() { synchronized(dimensionsLock) { /*Long time operation*/ } } }
1.6.3 冲突集合
设想有一个Inventory类,它有store和retrieve方法来存取对象。以下的例子中使用了Hashtable来演示,虽然这种完全同步的Hashtable允许Inventory类的实现无需考虑底层的实现细节。但是,我们仍然想store和retrieve方法添加一些语义上的约束,如下:
- retrieve操作不应该和store操作并发执行。
- 两个或者两个以上的retrieve方法不应该同时执行。
- 两个或者两个以上的store方法可以同时执行。
以下的非正规符号描述了冲突集合,即不能并发的方法对的集合.
{(store, retrieve), (retrieve, retrieve)}
基于冲突集合的类可以使用before/after这种模式,即基本操作被那些维护者独占关系的代码所环绕。首先,对于每个方法,定义一个计数变量,用以表示该方法是否在执行中。其次,把每个基本操作都隔离入非公共方法中。最后,编写那些基本操作的公共版本,即在那些基本操作的前后添加上before/after的控制。以下是个示例代码:
public class Inventory { protected final Hashtable items = new Hashtable(); protected final Hashtable suppliers = new Hashtable(); protected int storing = 0; protected int retrieving = 0; public void store(String desc, Object item, String supplier) throws InterruptedException { synchronized(this) { while(retrieving != 0) { wait(); ++storing; } } try { doStore(desc, item, supplier); } finally { synchronized(this) { if(--storing == 0) { notifyAll(); } } } } public Object retrieve(String desc) throws InterruptedException { synchronized(this) { while(storing != 0 || retrieving != 0) { wait(); ++retrieving; } } try { return doRetrieve(desc); } finally { synchronized(this) { if(--retrieving == 0) { notifyAll(); } } } } protected void doStore(String desc, Object item, String supplier) { items.put(desc, item); suppliers.put(supplier, desc); } protected Object doRetrieve(String desc) { Object x = items.get(desc); if(x != null) { items.remove(desc); } return x; } }
接下来考虑一个更复杂的例子,一个读出者和写入者模型,与Inventroy不同,读出者和写入者策略不仅应用于特定方法,而是控制所有具有读出和写入语义的方法。假设我们需要进行有目的的锁定(intention lock),比如,要求按照write,read,write,read,write的顺序等。这时候我们需要考虑的有以下几点:
- 如果当前已经存在一个或者多个活动(执行中)的读出者,而且有一个写入者正在等待的时候,一个新的读出者是否能否立即加入?如果答案是肯定的话,那么不断增加的读出者将会使写入者无法执行;如果答案为否,那么读出者的吞吐量就会下降。
- 如果某些读出者与写入者同时在等待一个活动的写入者完成操作,那么你的处理策略会偏向读出者还是写入者?先到者优先?随意?轮流?
虽然以上策略没有明确的答案,但是一些标准的解决方案和相关的实现还是存在的,以下一个通用的实现,使用了模板类和before/after这种模式,其子类版本不需要做过多的修改。而且可以通过让allowReader和allowWriter方法中的谓词依赖与这个值,来调整控制策略。以下是示例代码:
public abstract class ReadWrite { protected int activeReaders = 0; protected int activeWriters = 0; protected int waitingReaders = 0; protected int waitingWriters = 0; protected abstract void doRead(); protected abstract void doWrite(); public void read() throws InterruptedException { beforeRead(); try { doRead(); } finally { afterRead(); } } public void write() throws InterruptedException { beforeWrite(); try { doWrite(); } finally { afterWrite(); } } protected boolean allowReader() { return waitingWriters == 0 && activeWriters == 0; } protected boolean allowWriter() { return activeReaders == 0 && activeWriters == 0; } protected synchronized void beforeRead() throws InterruptedException { ++waitingReaders; while(!allowReader()) { try { wait(); } catch(InterruptedException ie) { --waitingReaders; throw ie; } } --waitingReaders; ++activeReaders; } protected synchronized void afterRead() { --activeReaders; notifyAll(); } protected synchronized void beforeWrite() throws InterruptedException { ++waitingWriters; while(!allowWriter()) { try { wait(); } catch(InterruptedException ie) { --waitingWriters; throw ie; } } --waitingWriters; ++activeWriters; } protected synchronized void afterWrite() { --activeWriters; notifyAll(); } }
发表评论
-
Understanding the Hash Array Mapped Trie
2012-03-30 10:36 0mark -
Atomic Bit Operation in Linux Kernel
2012-02-08 00:27 1979Linux Kernel支持atomic bit operat ... -
A Hierarchical CLH Queue Lock
2012-01-14 19:01 2110A Hierarchical CLH Queue Lock ( ... -
Inside AbstractQueuedSynchronizer (4)
2012-01-08 17:06 3464Inside AbstractQueuedSynchroniz ... -
Inside AbstractQueuedSynchronizer (3)
2012-01-07 23:37 4595Inside AbstractQueuedSynchroniz ... -
Inside AbstractQueuedSynchronizer (2)
2012-01-07 17:54 6304Inside AbstractQueuedSynchroniz ... -
Inside AbstractQueuedSynchronizer (1)
2012-01-06 11:04 7888Inside AbstractQueuedSynchroniz ... -
Code Optimization
2011-10-14 00:11 1558当前开发人员在进行编码的时候,可能很少关注纯粹代码级别的优化了 ... -
Distributed Lock
2011-08-02 22:02 91321 Overview 在分布式系统中,通常会 ... -
What's New on Java 7 Phaser
2011-07-29 10:15 81411 Overview Java 7的并 ... -
Sequantial Lock in Java
2011-06-07 17:00 21661 Overview Linux内核中常见的同步机 ... -
Feature or issue?
2011-04-26 22:23 121以下代码中,为何CglibTest.intercept ... -
Bloom Filter
2010-10-19 00:41 50191 Overview Bloom filt ... -
Inside java.lang.Enum
2010-08-04 15:40 64041 Introduction to enum J ... -
Open Addressing
2010-07-07 17:59 33951 Overview Open addressi ... -
JLine
2010-06-17 09:11 10949Overview JLine 是一个用来处理控 ... -
ID Generator
2010-06-14 14:45 1633关于ID Generator,想 ... -
inotify-java
2009-07-22 22:58 82081 Overview 最近公 ... -
Perf4J
2009-06-11 23:13 84301 Overview Perf4j是一个用于计算 ... -
Progress Estimator
2009-02-22 19:37 1485Jakarta Commons Cookbook这本书 ...
相关推荐
java concurrent 阻塞队列 线程 里面有详细的例子,下载后请认真阅读里面的内容,可能有点难以理解,请耐心
Java Concurrent in practice (animated)
java concurrent 包 详细解析
使用java concurrent调用xmlp api生成pdf
JAVA的CONCURRENT用法详解.pdf
java concurrent 多线程 PPT
资深Java专家10年经验总结,全程案例式讲解,首本全面介绍Java多线程编程技术的专著 结合大量实例,全面讲解Java多线程编程中的并发访问、线程间通信、锁等最难突破的核心技术与应用实践 封底 Java多线程无处不在,...
1. java.util.concurrent - Java 并发工具包 2. 阻塞队列 BlockingQueue 3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 ...
Java Concurrent处理并发需求.txt
java并发工具包 java.util.concurrent中文版pdf
详细的java 多线程相关知识 并附有相关练习题
java concurrent包分类结构图
EBS java concurrent program的实现
java同步大杀器concurrent 包java同步大杀器concurrent 包java同步大杀器concurrent 包java同步大杀器concurrent 包java同步大杀器concurrent 包java同步大杀器concurrent 包java同步大杀器concurrent 包java同步大...
JUC使用指导手册 http://tutorials.jenkov.com/java-util-concurrent/blockingqueue.html 中文译文
如何启动:以win7系统为例,最好jdk8 1.打开cmd,cd到jdk的path,本机是:cd C:\Java\...3.使用java -cp命令: java -cp D:\javaConcurrentAnimated.jar vgrazi.concurrent.samples.launcher.ConcurrentExampleLauncher
Concurrent Programming in Java - Design Principles and Patterns
JAVAConcurrent Programming in Java 对于一些JAVA 理解
资源JavaConcurrent实用知识库分享知识分享
JAVA后台程序以及java.concurrent包的应用