《实战Java...》读书笔记2

10、锁消除也是一种优化技术,一个例子是在不需要同步的地方使用了线程安全的数据结构,比如在线程的局部变量中使用了Vector,一个线程的局部变量是不能被其他线程访问的,不存在多线程问题,虚拟机检测到这样的问题就会将不必要的锁去除。

 

11、关于ThreadLocal,ThreadLocal是为了让每个线程都拥有一个对象的副本,多个线程之间不存在相互干扰。具体实现上,每个线程都持有一个ThreadLocal.ThreadLocalMap对象,这个ThreadLocalMap对象的key是一个ThreadLocal,value是这个ThreadLocal所对应的泛型的一个实例。为什么要用一个map,可能是因为一个线程会有多个ThreadLocal类型的引用,这个map跟HashMap不一样,Entry是WeakReference<ThreadLocal>的一个子类,然后没有next域,也就是不是拉链法。

    在使用ThreadLocal时,总是先尝试调用get获取值,如果获取不到就调用set设置值,这两个方法差不多,以get为例,首先要得到当前线程,再得到当前线程的ThreadLocalMap,然后从ThreadLocalMap中取值。代码如下:

    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();

}

 

12、关于AtomicInteger,这是使用CAS操作(Compare and Swap)实现的线程安全的类型。AtomicInteger可以当做Integer来用,只不过是线程安全的就是了,多线程之间可以直接共享以及更改AtomicInteger类型,而不用加锁。下面以incrementAndSet为例分析AtomicInteger的实现。其代码如下:

    public final intincrementAndGet() {

        for (;;) {

            int current = get();

            int next = current + 1;

            if (compareAndSet(current, next))

                return next;

        }

}

incrementAndGet方法表示将当前值加1,并返回新值。其中里面的无限循环表示不断尝试,直到成功为止。get()表示获取当前值,compareAndSet(current,next)表示如果AtomicInteger变量的当前值为current则将其改为next,成功返回true,如果compareAndSet方法不成功,则不断获取新的当前值,并在当前值上加1,不断尝试,直到成功为止。这个方法不错,简单有效。现在很多处理器都支持CAS操作。

    和AtomicInteger类似的类还有AtomicLong用来代替long型,AtomicBoolean表示boolean型,AtomicReference表示对象引用。

 

13、带有时间戳的对象引用:AtomicStampedReference。《实战Java高并发程序设计》里提到了CAS操作的一个局限性,就是有时候不知道一个对象是否被发生改动,比如有两个线程A,B,A先读变量var,发现其值为1,要将其改为2,在A读var并打算改var的这段时间,B改动了var的值,它将var改成2又改成1,那么在A看来,var好像并没有改,仍然将其值设置为2。这个例子是没有错的,但有时候对象是否改动会影响行为,比如书中举的送20元优惠的例子。这个时候AtomicReference就无能无力了,需要使用AtomicStampedReference。

 

14、不变模式:就是一个对象创建之后就不能改了,内部数据不能改了,不变模式的对象天然具有线程安全性,因为大家都不能改嘛。创建一个不变对象需要下面三点:

    1)去掉setter方法以及所有修改自身属性的方法。

    2)将所有属性设置为private final,类的修饰符也需要有final,这样这个类就无法被继承。

    3)有一个可以创建完整对象的构造函数,不然属性怎么初始化。

JDK中不变模式应用非常广泛,其中最典型的就是java.lang.String类。此外所有的元数据包装类,都是使用不变模式实现的,比如Boolean,Byte,Character,Double等。

 

15、《实战Java高并发程序设计》里提到了一个Future模式,我们知道有些任务是需要有返回值的,这些任务可以实现Callable<V>接口,并且实现call()方法,而不是实现Runnable接口。我们在将任务提交到线程池的时候,(executorService.submit())会返回一个Future<V>对象,可以调用这个future.get()来获取返回值。

    Future模式的核心思想是异步调用。也就是说我们在调用future.get()方法之前可以干一些其他事情,不至于阻塞在future.get()方法上。当然如果其他事情干完了,还没有返回结果,还是要阻塞的。

    《实战Java…》提供了一种实现Future模式的方法,那就是在调用submit()的时候立即返回一个代理,这个代理持有真实数据的一个引用,调用这个代理的get方法返回的是真实数据(得不到就阻塞)。

 

16、矩阵并行计算的关键是如何划分矩阵,矩阵划分的不对就不能执行并行计算。在进行矩阵划分时,将左边的矩阵横着划分为两半(横着画一条线),将右边的矩阵竖着划分为两半,这样在进行矩阵乘法时,相互分块之间互不影响,可以并行计算,利用Fork/Join框架计算矩阵并行计算不错。

 

17、这本书还提到了一个高并发分布式框架Akka,好像很值得看一下。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值