Java多线程——5 阻塞型同步、非阻塞型同步和Lock-Free

关于多线程并发,该采用Lock还是Free,其实这都是各有弊端的。

相比于Lock,CAS 原语在轻度和中度争用情况下确实可以大幅度提高程序性能。

但CAS的弊端同时也在限制,CAS 的原子性完全取决于硬件实现。大多数 Intel 和 AMD 的 CPU 采用了一种叫做 MOSEI 缓存一致性协议来管理缓存。这种架构下,处理器缓存内 CAS 操作相对成本低廉。但一旦资源争用,就会引起缓存失效和总线占用。缓存越失效,总线越被占用,完成 CAS 操作也越被延迟。缓存争用是程序可伸缩性杀手。当然对于非 CAS 内存操作来说也是如此,但 CAS 情况更加槽糕。同时CAS 操作要比普通内存操作花费更多 CPU 周期。这归功于缓存分级的额外负担、刷新写缓冲区与穿越内存栅栏限制和需求以及编译器对 CAS 操作优化的能力。


CAS这是由硬件提供原子操作指令实现的。在非激烈竞争的情况下,开销更小,速度更快。java.util.concurrent中实现的原子操作类包括:AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference

看一下Java的Lock-Free算法

采用synchronized关键字实现

class Counter
{
	private volatile int max = 0;
	//若要线程安全,需要加锁
	public synchronized void set(int value)
	{
		if (value > max)
		{
			max = value;
		}
	}
	public int getMax()
	{
		return max;
	}
}

采用CAS原子指令实现

class Counter
{
	private AtomicInteger max = new AtomicInteger();

	// LockFree算法,不需要加锁。通常都是三个部分组成:① 循环 ② CAS (CompareAndSet) ③ 回退
	public void set(int value)
	{
		for (;;)
		{
			int current = max.get();
			if (value > current)
			{
				if (max.compareAndSet(current, value))
				{
					break;
				} else
				{
					continue;
				}
			} else
			{
				break;
			}
		}
	}

	public int getMax()
	{
		return max.get();
	}
}

进一步使用Lock-Free数据结构

class BeanManager
{
	/*
	 * ConcurrentHashMap并没有实现Lock-Free,只是使用了
	 * 分离锁(锁由数据结构来管理)的办 法使得能够支持多个Writer并发。
	 * ConcurrentHashMap需要使用更 多的内存。
	 */
	private ConcurrentMap map = new ConcurrentHashMap();

	public Object getBean(String key)
	{
		Object bean = map.get(key);
		if (bean == null)
		{
			map.putIfAbsent(key, createBean());
			bean = map.get(key);
		}
		return bean;
	}

	private Object createBean()
	{
		return new Integer((int) Math.random() * 1000);
	}
}


ConcurrentHashMap功能规范和HashTable一样,关于ConcurrentHashMap的详细介绍

http://hill007299.iteye.com/blog/1490779


锁的使用
① 使用支持CAS的数据结构,避免使用锁,如:AtomicXXX、ConcurrentMap、CopyOnWriteList、ConcurrentLinkedQueue
② 一定要使用锁的时候,注意获得锁的顺序,相反顺序获得锁,就容易产生死锁。
③ 死锁经常是无法完全避免的,鸵鸟策略被很多基础框架所采用。
④ 通过Dump线程的StackTrace,例如linux下执行命令kill -3 ,或者jstack –l ,或者使用Jconsole连接上去查看线程的StackTrace,由此来诊断死锁问题。
⑤ 外部锁常被忽视而导致死锁,例如数据库的锁
⑥ 存在检测死锁的办法
⑦ 存在一些预防死锁的手段,比如Lock的tryLock,JDK 7中引入的Phaser等。


对于CAS,同样的思路用于更新数据库-乐观锁,先比与悲观锁不需要使用锁,从而开销更小,速度更快。在这里对于乐观锁和悲观锁就不多讲了

你可能感兴趣的:(Java并发编程,Java)