`
frenchmay
  • 浏览: 229154 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

提高并发程序的可伸缩性的7个技巧

阅读更多

并发程序的可伸缩性主要是在保证程序安全同步,操作准确的前提下,保障程序在大量线程并发的情况下访问共享同步资源的效率.锁住某个共享的资源以获得独占式的访问这种做法会形成可伸缩性瓶颈――它使其他线程不能访问那个资源,即使有空闲的处理器可以调用那些线程也无济于事。为了取得可伸缩性,我们必须消除或者减少对独占式资源锁的依赖。

基于这种原理有如下几种解决方案,部分内容整理于ibm developerworks.

1 减小锁粒度

public class ShareHashMap {
	
	private static final Map<Integer,Map<String ,Object>> shareMap =
							 new HashMap<Integer,Map<String ,Object>>();
	
	public void addValue(Integer index,String key,Object value){
		checkIndex(index);
		shareMap.get(index).put(key, value);
	}
	
	public void addValue2(Integer index,String key,Object value){
		checkIndex(index);
		synchronized(shareMap.get(index)){
			shareMap.get(index).put(key, value);
		}	
	}
	
	public Object getValue(Integer index,String key){
		checkIndex(index);
		return shareMap.get(index).get(key);
	}
	
	public Object getValue2(Integer index,String key){
		checkIndex(index);
		synchronized(shareMap.get(index)){
			return shareMap.get(index).get(key);
		}	
	}
	
	private void checkIndex(Integer index){
		if(null==index){
			return;
		}
		synchronized(shareMap){
			if(null==shareMap.get(index)){
				shareMap.put(index, new HashMap<String ,Object>());
			}
		}
	}
}

  提高 HashMap 的并发性同时还提供线程安全性的一种方法是废除对整个表使用一个锁的方式,而采用对hash表的每个bucket都使用一个锁的方式(或者,更常见的是,使用一个锁池,每个锁负责保护几个bucket) 。这意味着多个线程可以同时地访问一个 Map 的不同部分,而不必争用单个的集合范围的锁。这种方法能够直接提高插入、检索以及移除操作的可伸缩性。不幸的是,这种并发性是以一定的代价换来的――这使得对整个 集合进行操作的一些方法(例如 size() isEmpty() )的实现更加困难,因为这些方法要求一次获得许多的锁,并且还存在返回不正确的结果的风险。然而,对于某些情况,例如实现cache,这样做是一个很好的折衷――因为检索和插入操作比较频繁,而 size() isEmpty() 操作则少得多。

 

实现1,为每个线程分配一个Integer类型的值,每个线程独享唯一一个键值对.这个原理和threadLocal的原理差不多,为每个线程分配独享的数据区域.下面是直接以当前线程为索引值,创建空间的一种实现.

 

public class ThreadHashMap {
	private static final Map<Thread,Map<String ,Object>> shareMap =
								 new HashMap<Thread,Map<String ,Object>>();
	
	public void addObject(String key,Object value){
		checkThread();
		shareMap.get(Thread.currentThread()).put(key, value);
	}
	
	public Object getObject(String key){
		checkThread();
		return shareMap.get(Thread.currentThread()).get(key);
	}
	
	private void checkThread(){
		Thread t = Thread.currentThread();
		synchronized(shareMap){
			if(null==shareMap.get(t)){
				shareMap.put(t, new HashMap<String ,Object>());
			}
		}
	}
}
 

 

实例2,运行多个线程读写同一个键值对,虽然也存在锁定,但是效率要比整个锁住整个hashmap要好的多.

 

2. 使用非堵塞的编程方式

使用ConcurrentHashMap,NIO等非堵塞资源提供方式.

如果拥有一个互斥锁,但是却堵塞导致其他线程等待甚至饥饿,是极其应该避免的.

具体内容可以见我在javaeye发布的文章线程,非堵塞队列和线程池相关小贴士

3. 根据访问操作的特征选择合适的数据结构.

如果读操作远高出写操作,建议使用类似org.apache.commons.collections的FastHashMap等快速集合,但是要注意

FastHashMap的写操作效率是很低的,写线程比较多的情况下很容易堵塞,另外FastHashMap是 以slow的方式运行的,要通过设置才能以fast模式运行,关于更多的FastHashMap内容可以看我在javaeye的另外一篇文章:关于FastHashMap

4. 合理使用线程池技术

线程池的使用一方面是为了节省线程创建的资源,或者例如网络连接,数据库连接只有有限的资源为了最大限度的利用这些资源,另一方面也是为了避免同时运行大量的线程,避免cpu在线程切换间浪费大量的资源.

5.CopyOnWrite

		Vector<String> v = new Vector<String>();
		for(int i=0;i<v.size();i++){
			v.get(i);
		}

 vector是线程安全的,但是通过索引遍历vector并不是安全的,虽然size()和get()方法每次调用都是线程安全的,但是遍历操作本身应该视为一个事务来处理,事务是具有原子性的.如果临时插入或者删除一个元素,导致index发生变更就有可能读取重复或者少读取元素.可以拷贝一个vecotr的副本,对副本进行遍历操作.

6. 锁崩溃

与其在获取锁和释放锁之间切换,不如一直占有锁,把当前的工作完成.获取您已占用的锁比获取无人占用的锁要快得多。

7.减小锁占用的时间

不要把和同步无关的代码,预处理代码和后期处理代码都放在同步块中.

分享到:
评论

相关推荐

    响应式架构 消息模式Actor实现与Scala.Akka应用集成

    通过Actor模型使用响应式消息传输模式,可编写出具有高性能、高响应性、高可伸缩性和高韧性的并发应用程序。本书由10章构成,详细介绍了使用Actor模型中响应式消息传输模式的理论和实用技巧。其中包括:Actor模型和...

    响应式架构 消息模式Actor实现与Scala.Akka应用集成.rar

    通过Actor模型使用响应式消息传输模式,可编写出具有高性能、高响应性、高可伸缩性和高韧性的并发应用程序。《响应式架构:消息模式Actor实现与Scala、Akka应用集成》由10章构成,详细介绍了使用Actor模型中的响应式...

    AppFramework_V1.0

    使用AppFramework数据库访问组件,可以降低企业的开发人员培训成本,提高产品的开发速度,提高产品稳定可靠性,提高产品的可伸缩性和可移植性。下文将分入门、精通、高级三个篇章,详细讲述如何使用AppFramework...

    AppFramework_V1.0_New

    使用AppFramework数据库访问组件,可以降低企业的开发人员培训成本,提高产品的开发速度,提高产品稳定可靠性,提高产品的可伸缩性和可移植性。下文将分入门、精通、高级三个篇章,详细讲述如何使用AppFramework...

    提升Java的锁性能

    几个月前我们介绍了如何通过Plumbr来进行线程锁检测,随后便收到了很多...毕竟,从“常识”来讲,锁的性能是很差的,并且还限制了程序的可伸缩性。如果你怀揣着这样的想法去优化代码并删除锁的话,后你肯定会引入一些难

    AppFramework数据库访问组件_代码生成插件_V1.1.rar

    使用AppFramework数据库访问组件,可以降低企业的开发人员培训成本,提高产品的开发速度,提高产品稳定可靠性,提高产品的可伸缩性和可移植性。下文将分入门、精通、高级三个篇章,详细讲述如何使用AppFramework...

    SQLServer2008查询性能优化 2/2

    最后以一个实际的工作负载将所有技巧联系起来,并且提供了“宝典”式的最佳实践列表。 《SQL Server 2008查询性能优化》适合于关心数据库应用系统性能的开发人员和数据库管理人员阅读。通过阅读《SQL Server 2008...

    SQLServer2008查询性能优化 1/2

    最后以一个实际的工作负载将所有技巧联系起来,并且提供了“宝典”式的最佳实践列表。 《SQL Server 2008查询性能优化》适合于关心数据库应用系统性能的开发人员和数据库管理人员阅读。通过阅读《SQL Server 2008...

Global site tag (gtag.js) - Google Analytics