java并发的方式

    面试的时候问,java有些什么并发的方式解决竞争条件,经常得到的回答是:synchronized, 我承认,这个回答没有问题。但是,能够再深入一点,再全面一点吗?

    让人觉得眼前一亮的回答是:按照性能从坏到好,可以分为阻塞式加锁,非阻塞式加锁,无锁几种情况。

    阻塞式加锁:即采用synchronized和ReentrantLock(还可以顺便说一下自旋锁,偏向锁等等),他们都是重量级的操作,使用ReentrantLock,常常是为了其他的特性,比如公平锁,条件,可中断等特性。当然,也可能是为了性能的原因。下图就是两种机制的性能测试(注:见后面参考)。


    中间的一个小插曲是volatile,volatile可以轻量级的让变量在所有线程立即可见以及禁止指令重排。

    举个例子,下面的increase在不加锁的情况下被多个线程调用是否安全的完成我们想要的语义?

private volatile int race = 0;
public void increase(){
    race++;
}

    非阻塞式加锁:我想,如果你不了解CAS的话肯定out了,没错,非阻塞式加锁就是所谓的乐观锁,它不会尝试先锁后操作,而是尝试先操作,如果没有冲突,就表示成功了,但是如果有冲突,再采取其他的补偿措施(如重试)。非阻塞式加锁是靠硬件指令集的发展才带动起来的。常见的非阻塞式加锁指令有,测试并设置(test-and-set),获取并增加(fetch-and-increment),交换(swap),比较并交换(compare-and-swap,即CAS)。上面的代码,如果换成

private AtomicInteger race = new AtomicInteger(0);
public void increase(){
    race++;
}

     无锁策略:分三类:1).不可变类。说明该类是类似String的对象,所谓的不可变,即将该类中的状态声明为final,表明此状态不再能够修改,比如String

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence
{
    private final char value[];
    ...
}
                                          2)线程封闭(栈封闭)。这是我比较推崇的一种方式,如果一个方法只依赖于传进来的参数而不依赖于对象的状态,则这个方法就是可重入的,简单的讲就是这个方法不要调用对象中的实例变量,通过这种方式可以减少很多不必要的同步。举个例子,相信你经常听到servlet中尽量不要定义和调用实例变量,因为每个请求都会被一个线程调用,然后去调用同一个servlet的同一个方法,如果该方法用了实例变量,势必造成错误。

                                          3)ThreadLocal。ThreadLocal相当于一个每个线程都有一个变量的保管箱,最好的理解方式就是把它想象成一个以线程为key,你要保管的实例为value的hashmap。事实上也是这样。在ThreadLocal的源码中,你会发现ThreadLocal将this传入作为key来查找变量。

public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }

参考:reentrantLock与synchronized性能测试 http://www.ibm.com/developerworks/library/j-jtp10264/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值