近期小结

CompletableFuture 是jdk8提供的异步类,远比Future强大!
问题是:thenRun/thenRunAsync 啥关系?使用另一个线程完成,就是说不对主线程造成影响吗???
小知识:该类的多数async方法,都有两种重载形式,一种是使用默认的fork/join框架,一种是提供threadpool。

ConcurrentHashMap,可以支持超过Integer.MAX的键值对,但size()只能返回int,所以JDK8又添加了一个mapCount()方法。

我们已知JDK中的AtomicXxx类(如AtomicInteger),提供了在非同步环境下的原子操作。
如常见的atomic.incrementAndGet(),其实就等同于++i,以及等同于i++的getAndIncrement(),还有--i/i--/i+n/i-n等操作。
这些操作虽然保证了原子性,但是如果你想同时调用两个方法,如get()之后再做判断再设置,那这就是两个独立的原子操作,合起来就不是原子操作啦!
这时就需要do{..} while(!atomic.compareAndSet(oldVal, newVal))了,就是所谓的CAS来保证同步!

JDK8中还提供了简单的方法:updateAndGet和accumulateAndGet,都是接收lambda,本质是一样的,可以看一下源码。
当然,不要怀疑do{..} while(!atomic.compareAndSet(oldVal, newVal))的性能,因为会映射成一个底层的处理器操作,所以效率极高,比用锁快的多。

一般情况下这些原子类是足够了,但还有一些情况会出现效率问题,如很多线程同时竞争,因为一直比较,会导致严重的性能问题。
如果你不需要在中途获取最终的值,那完全可以使用LongAdder或LongAccumulator -- 只需要在最后累积一下即可,效率极高。
LongAdder可以看作LongAccumulator的特殊情况:new LongAccumulator(Long::sum, 0L);。
就不多说了。

最后再次呼吁大家使用JDK8的日期、时间API,相当无敌。
举个例子:①计算你到现在总共生活了多少天?②列出21世纪所有的周五。

// 计算出生到现在过去了多少天
@Test
public void days(){
    long days = LocalDate.now().until(LocalDate.of(2000, 9, 1), ChronoUnit.DAYS);
    System.out.println("从出生到现在,总共过去这么多天: " + Math.abs(days));
}

// 列出21世纪所有的星期五
@Test
public void fridays(){
    List<LocalDate> list = new ArrayList<>(6000);// 55*100
    LocalDate start = LocalDate.of(2000, 1, 1);
    LocalDate end = LocalDate.of(2099, 12, 31);

    // 防止第一天就是周五,先执行一次nextOrSame
    LocalDate tmp = start.with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY));
    if(tmp.isEqual(start)){
        System.out.println("第一天就是周五啦!");
    }
    // 然后,循环计算后面的周五
    do{
        list.add(tmp); // 第一次是上面计算的周五
        tmp = tmp.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));
    } while(tmp.isBefore(end));

    System.out.println(list.size());
    System.out.println(list.get(0));
    System.out.println(list.get(list.size() - 1));
}
原文地址:https://www.cnblogs.com/larryzeal/p/7634795.html