指令重排序的证明

public class ReOrderDemo {
    private static int a;
    private static int b;
    private static int x;
    private static int y;


    public static void main(String[] args) throws InterruptedException {

        for (int i = 0; ; i++) {
            a=0;
            b=0;
            x=0;
            y=0;
            Thread aThread = new Thread(new Runnable() {
                public void run() {
                    a = 1;
                    x = b;
                }
            });
            Thread bThread = new Thread(new Runnable() {
                public void run() {
                    b = 1;
                    y = a;
                }
            });
            bThread.start();
            aThread.start();
            aThread.join();
            bThread.join();
            if (x==0&&y==0) System.out.println(String.format("第%s次loop出错",i));
        }
    }
}
//程序输出:
第5255461次loop出错

Process finished with exit code -1

Java四种线程池

  • new Thread()的弊端: 1、每次新建对象性能差 2、缺乏统一管理,可无限创建线程,相互竞争,消耗系统资源 3、缺乏丰富功能

要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,很有可能配置的线程池不是较优的,因此在Executors类里面提供了一些静态工厂,生成一些常用的线程池。

newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。 newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。 newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

设计一个多线程程序

题目要求:
多线程发起多个任务, 所有任务成功返回成功, 任何一个任务失败导致失败, 越快越好.

答案參考廖雪峰的CompletableFuture 以及这里

使用传统的Future

//使用传统的Future, 要么使用isDone轮询, 要么阻塞等待返回值.
public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newCachedThreadPool();
        Future<String> task = executor.submit(() -> {
            System.out.println("start");
            Thread.sleep(3000);
            return "finished";
        });
        System.out.println(task.get());
        executor.shutdown();
    }

使用Java8新增的CompletableFuture类

Netty、Guava分别扩展了Java 的 Future 接口,方便异步编程。Java 8新增的CompletableFuture类正是吸收了所有Google Guava中ListenableFuture和SettableFuture的特征,还提供了其它强大的功能,让Java拥有了完整的非阻塞编程模型: Future、Promise 和 Callback(在Java8之前,只有无Callback 的Future)。

CompletableFuture能够将回调放到与任务不同的线程中执行,也能将回调作为继续执行的同步函数,在与任务相同的线程中执行。 它避免了传统回调最大的问题,那就是能够将控制流分离到不同的事件处理器中。

CompletableFuture弥补了Future模式的缺点。在异步的任务完成后,需要用其结果继续操作时,无需等待。 可以直接通过thenAccept、thenApply、thenCompose等方式将前面异步处理的结果交给另外一个异步事件处理线程来处理。

方法名 描述
runAsync(Runnable runnable) 使用ForkJoinPool.commonPool()作为它的线程池执行异步代码。
runAsync(Runnable runnable, Executor executor) 使用指定的thread pool执行异步代码。
supplyAsync(Supplier supplier) 使用ForkJoinPool.commonPool()作为它的线程池执行异步代码,异步操作有返回值
supplyAsync(Supplier supplier, Executor executor) 使用指定的thread pool执行异步代码,异步操作有返回值

runAsync 和 supplyAsync 方法的区别是runAsync返回的CompletableFuture是没有返回值的.