Java并发编程系列:锁优化

单核的并行算法的效率要低于原始串行的算法,因为并行多线程多了线程调度、上下文切换等开销。而单线程器主要资源都花在 任务本身,他不需要维护数据结构的一致性,也不需要为线程的切换和调度花费时间。并行计算之所以能提高系统的性能,而是因为他更合理的进行任务调度,充分利用各个CPU的资源,合理的并发,才能将CPU的性能发挥到极致。

在高并发的环境下,激烈的所竞争会导致程序的性能下降。

1.减少锁的持有时间

在必要时进行同步控制,这样能明显减少线程持有锁的时间,从而有利于降低锁冲突的可能性,进而提升系统的并发能力。

2.减小锁粒度

对于ConcurrentHashMap,他的内部进一步细分了若干个hashMap(称为SEGMENT),默认情况下一个ConcurrentHashMap可被进一步细分为16个段。当加入一个新的元素是,不是将HashMap加锁,而是根据Hashcode得到该表对应的那个段中,然后对段加锁,完成put操作。如果在多线程环境中,多个线程同时进行put操作,只要加入的元素不在同一个段内,则线程间可以真正的并行。
减少锁粒度,是指缩小锁定对象的范围,从而减少锁冲突的可能性,进而提高系统并发里。

3.读写分离锁

在读多写少的场合,如果系统读写数据时均使用独占锁,那么读读、写写、读写操作间不能做到真正的并发,并且要相互等待,而读操作不会影响数据的完整性和一致性。

4.锁分离

典型的案例是LinkedBlockingQueue,因为它是由链表实现的,take()和put()分别是从队列中取数据和往队列中添加数据的功能。虽然两个函数都是对当前队列进行修改操作,可是他们分别作用于队头和对尾。JDK的实现中采用了两把不同的锁,分离了take和put操作。从而take只和take线程竞争,put只和put竞争,减少了锁竞争的可能性。

	public E take() throws InterruptedException {
		E x;
		int c = -1;
		final AtomicInteger count = this.count;
		final ReentrantLock takeLock = this.takeLock;
		//takelock不允许有两个线程同时取数据
		takeLock.lockInterruptibly();
		try {
		    while (count.get() == 0) {
			//如果没有数据可取是,进入等待,当有notEmpty.signal方法调用时,才唤醒
		        notEmpty.await();
		    }
			//取得对头数据
		    x = dequeue();
		    c = count.getAndDecrement();
		    if (c > 1)
				//通知其他take()操作
		        notEmpty.signal();
		} finally {
		    takeLock.unlock();
		}
		if (c == capacity)
		    signalNotFull();
		return x;
	}
5.锁粗化

当有一连串持续的对同一锁进行请求和释放的操作时,表可以把所有的所操作整合成对锁的一次请求释放,从而减少对锁的请求次数,这个操作叫做锁粗化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值