`
臻是二哥
  • 浏览: 182647 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
博客专栏
Group-logo
Java技术分享
浏览量:0
社区版块
存档分类
最新评论

JAVA并发-减少锁的竞争

阅读更多
降低锁的竞争可以提高并发程序的性能和可伸缩性,有3种方式可以降低锁的竞争:
1. 减少锁的持有时间(缩小锁的范围)
2. 降低锁的请求频率(降低锁的粒度)
3. 放弃使用独占锁,使用并发容器,原子变量,读写锁等等来代替它。


减少锁的持有时间(减小锁的范围):
减少锁的持有时间实际上就是减小锁的控制范围,将一些并不需要锁的操作从同步代码块中移除。如下所示,需要进行同步操作的只有attributes.get(key);这一行代码。
//可以优化的代码
class AttributeStore{
	private final Map<String,String> attributes=new HashMap<String,String>();
	public synchronized boolean userLocationMatches(String username,String regex){
		String key="user."+username;
		String location=attributes.get(key);
		if(location==null)
			return false;
		else
			return Pattern.matches(regex,location);
	}
}

缩小锁的范围如下,将不需要同步的内容移出代码块。
//优化之后的代码
class AttributeStore{
	private final Map<String,String> attributes=new HashMap<String,String>();
	public boolean userLocationMatches(String username,String regex){
		String key="user."+username;
		String location;
		synchronized (this) {
			location=attributes.get(key);			
		}
		if(location==null)
			return false;
		else
			return Pattern.matches(regex,location);
	}
}


降低锁的请求频率(降低锁的粒度):
通过将粗粒度的锁分解为多个细粒度的锁,从而将原来到一个锁的请求分担到多个锁。常用的方案是锁分解或锁分段(一个锁分解为两个锁称为锁分解,一个锁分解为多个锁称为锁分段)。在代码中,当一个锁需要同时保护多个互相独立的共享状态变量的时候,可以考虑锁分解或锁分段。
先来看一个锁分解的例子:
//可以锁分解的代码
class ServerStatus{
	private  Set<String> users;
	private  Set<String> queries;
	public synchronized void addUser(String user){
		users.add(user);
	}
	public synchronized void removeUser(String user){
		users.remove(user);
	}
	
	public synchronized void addQuery(String query){
		queries.add(query);
	}
	public synchronized void removeQuery(String query){
		queries.remove(query);
	}	
}

在上面的代码中,同一个ServerStatus对象锁用于保护2个独立的共享变量,可以使用锁分解。
//优化后的代码
class ServerStatus{
	private  Set<String> users;
	private  Set<String> queries;
	public  void addUser(String user){
		synchronized (users) {
			users.add(user);
		}
	}
	public  void removeUser(String user){
		synchronized (users) {
			users.remove(user);
		}
	}
	
	public  void addQuery(String query){
		synchronized (queries) {
			queries.add(query);
		}
	}
	public  void removeQuery(String query){
		synchronized (queries) {
			queries.remove(query);
		}
	}	
}


锁分段的典型应用是ConcurrentHashMap。在Collections.synchronizedMap()方法中,使用组合的方式将传入Map的方法放入同步代码块中执行,所有的同步代码块使用同一个对象锁。为了提高容器的性能,在ConcurrentHashMap容器中使用16个对象锁,每个对象锁保护所有散列桶的1/16,其中第N个散列桶由第(N%16)个对象锁来保护。大致的思路如下:
class MyMap<K,V>{
	static final class Node<K,V>{
		private K key;
		private V value;
		private Node<K,V> next;
		public Node<K, V> getNext() {
			return next;
		}
		//...set get equals hashCode...//
	}
	private final static int N_LOCKS=16;
	private Object[] mylocks;
	private Node<K,V>[] buckets;
	public MyMap(int num) {
		mylocks=new Object[N_LOCKS];
		for(int i=0;i<N_LOCKS;i++){
			mylocks[i]=new Object();
		}
		buckets=new Node[num];
	}
	
	public V get(K key){
		int bucketIndex=key.hashCode()%buckets.length;//定位目标所在的桶
		synchronized (mylocks[bucketIndex%N_LOCKS]) {//获取桶对应的锁
			for(Node<K,V> node=buckets[bucketIndex];node!=null;node=node.getNext()){
				if(key.equals(node.key))
					return node.value;
			}
			return null;
		}
	}
	//......
}


放弃使用独占锁:
我们可以放弃使用独占锁,使用并发容器,原子变量,读写锁等等来代替他。
1
0
分享到:
评论

相关推荐

    Java并发篇乐观锁,悲观锁,自旋锁

    轻量级锁并不是用来代替重量级锁的,它的本意是在没有多线程竞争的前提下,减少传统的重量 级锁使用产生的性能消耗。在解释轻量级锁的执行过程之前,先明白一点,轻量级锁所适应的场 景是线程交替执行同步块的情况...

    Java并发编程实战

    Java并发编程实战 本书深入浅出地介绍了Java线程和并发,是一本完美的Java并发参考手册。书中从并发性和线程安全性的基本概念出发,介绍了如何使用类库提供的基本并发构建块,用于避免并发危险、构造线程安全的类及...

    java并发编程:juc线程池

    而了解 Java 并发编程以及其中的 JUC(java.util.concurrent)线程池,对于构建高性能、高可伸缩性的应用程序具有重要意义。 多核处理器的出现使得并发执行成为一种重要的优化手段。了解并发编程和线程池的工作原理...

    Java并发的基础知识.docx

    时间片是CPU分配给各个线程的时间,因为时间非常短,所以CPU不断通过切换线程,让我们觉得是...可以参照jdk1.7分段锁的思想,不同的线程处理不同的数据,这样在多线程竞争的条件下,可以减少上下文切换的时间 CAS算法

    java关键字Synchronized详解

    偏向锁的主要目的是减少锁竞争,提高并发性能。当一个对象首次被创建时,JVM会自动为其分配偏向锁。此时,如果其他线程试图获取该对象的锁,JVM会将对象头中的Mark Word(指向对象头的指针)设置为偏向锁标识。这样,...

    一天搞定Java并发编程

    Java并发编程 一、并发编程的挑战 1.1 如何减少上下文切换 无锁并发编程:多线程竞争锁时,会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁,如将数据的ID按照Hash算法取模分段,不同的线程...

    Java几种线程池类型介绍及使用.docx

    1.使用new Thread()创建线程的弊端: 每次通过new Thread()创建对象...可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。 提供定时执行、定期执行、单线程、并发数控制等功能。

    xmljava系统源码-seckill::triangular_flag:使用SSM实现高并发秒杀

    Java高并发秒杀系统API 秒杀优化难点 这个项目中核心就是怎么样处理可能会发生高并发的地方,比如详情页、系统时间、地址暴露接口、用户执行秒杀操作。将商品详情页放在CDN中。用Redis去优化地址暴露接口和利用...

    JC工具

    JVM的Java并发工具。 该项目旨在提供JDK当前缺少的一些并发数据结构: 并发队列的SPSC / MPSC / SPMC / MPMC变体: SPSC-单一生产者单一消费者(免费,有界和无界) MPSC-多生产者单个消费者(较少锁定,有界和...

    sesvc.exe 阿萨德

    因此通常建议能提前预估 HashMap 的大小最好,尽量的减少扩容带来的性能损耗。 根据代码可以看到其实真正存放数据的是 transient Entry,V&gt;[] table = (Entry,V&gt;[]) EMPTY_TABLE; 这个数组,那么它又是如何定义的...

    ORACLE9i_优化设计与系统调整

    §3.5.5 JAVA脚本 81 第6章 性能优化基础知识 82 §5.1 理解ORACLE性能优化 82 §5.1.1 响应时间与吞吐量的折衷 82 §5.1.2 临界资源 83 §5.1.3 过度请求的影响 83 §5.1.4 调整以解决问题 83 §5.2 优化的执行者 ...

    Oracle 9i&10g编程艺术:深入数据库体系结构(全本)含脚本

    4.2.6 Java池 149 4.2.7 流池 150 4.2.8 自动SGA内存管理 150 4.3 小结 151 第5章 Oracle进程 153 5.1 服务器进程 153 5.1.1 专用服务器连接 154 5.1.2 共享服务器连接 156 5.1.3 连接与会话 157 5.1.4 ...

    二十三种设计模式【PDF版】

    要知道软件还有一个与建筑截然相反的责任和用途,那就是:现代社会中,计划感不上变化,竞争激烈,所有一切变幻莫测,要应 付所有这些变化,首推信息技术中的软件,只有软件能够帮助人类去应付各种变化.而这点正好与建筑想反...

    Oracle编程艺术

    1.3.2 理解并发控制...................................................................... 78 1.3.3 多版本.............................................................................. 84 1.3.4 数据库...

Global site tag (gtag.js) - Google Analytics