这里实际是考察线程间的通信,正常情况下,主线程里启动异步线程执行某个方法,理论上主线程和这个异步线程是并行执行,互不干扰,但是现在要求异步线程执行完毕方法之后,才能继续执行主线程,实际是如何阻塞主线程,到底有几种写法呢?废话少说,直接上代码!

首先先给出需要执行的方法(可以自定义):

public class Compute {

    public static int fibo(int a) {
        if ( a < 2) {
            return 1;
        }
        return fibo(a-1) + fibo(a-2);
    }

}

方式一:Thread.sleep()方法,让主线程休眠

代码:

public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();

        //异步执行
        new Thread(() -> {
            int result = Compute.fibo(7);
            System.out.println("异步线程执行结果:"+result);
        }).start();
        Thread.sleep(10000);
        System.out.println("main线程结束。。。");
    }

执行结果:

android 子线程阻塞后如何结束 子线程阻塞主线程_多线程

 

方式二:用join方法阻塞主线程

代码:

public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        myThread.join();
        System.out.println("main线程结束。。。");
    }

    private static class MyThread extends Thread{

        @Override
        public void run(){
            int result = Compute.fibo(7);
            System.out.println("异步线程执行结果:"+result);
        }
    }

执行结果:

android 子线程阻塞后如何结束 子线程阻塞主线程_thread_02

方式三:wait+synchronized阻塞主线程

代码:

public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();
        Object obj = new Object();
        MyThread myThread = new MyThread();
        myThread.start();
        synchronized (obj){
            obj.wait(1000);
        }
        System.out.println("线程:"+Thread.currentThread().getName()+" 使用时间:"+(System.currentTimeMillis()-start)+"ms");
    }

    private static class MyThread extends Thread{

        @Override
        public void run(){
            int result = Compute.fibo(7);
            System.out.println("线程:"+Thread.currentThread().getName()+" 异步计算结果:"+result);
        }
    }

执行结果:

android 子线程阻塞后如何结束 子线程阻塞主线程_System_03

方式四:wait+notify+synchronized

public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();
        Object obj = new Object();
        MyThread myThread = new MyThread(obj);
        myThread.start();
        synchronized (obj){
            obj.wait();
        }
        System.out.println("线程:"+Thread.currentThread().getName()+" 使用时间:"+(System.currentTimeMillis()-start)+"ms");
    }

    private static class MyThread extends Thread{
        Object obj;
        public MyThread(Object obj){
            this.obj = obj;
        }

        @Override
        public void run(){
            int result = Compute.fibo(7);
            System.out.println("线程:"+Thread.currentThread().getName()+" 异步计算结果:"+result);
            synchronized (obj) {
                obj.notify();
            }
        }

    }

执行结果:

android 子线程阻塞后如何结束 子线程阻塞主线程_thread_04

方式五:ReentrantLock+Condition

private final static ReentrantLock reentrantLock = new ReentrantLock(true);
    private final static Condition condition = reentrantLock.newCondition();

    public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();
        Object obj = new Object();
        //异步执行
        new Thread(() -> {
            ThreadWork05.handler(obj);
        }).start();
        ThreadWork05.mainHandler(start);
    }

    private static void mainHandler(long start) throws InterruptedException {
        try {
            reentrantLock.lock();
            condition.await();
            System.out.println("线程:"+Thread.currentThread().getName()+" 使用时间:"+(System.currentTimeMillis()-start)+"ms");
        }finally {
            reentrantLock.unlock();
        }
    }

    private static void handler(Object obj) {
        try {
            reentrantLock.lock();
            int result = Compute.fibo(7);
            System.out.println("线程:"+Thread.currentThread().getName()+" 异步计算结果:"+result);
            condition.signal();
        }finally {
            reentrantLock.unlock();
        }
    }

执行结果:

android 子线程阻塞后如何结束 子线程阻塞主线程_thread_05

方式六:CountDownLatch

public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(1);

        long start = System.currentTimeMillis();
        //异步执行
        new Thread(() -> {
            handler();
            latch.countDown();
        }).start();

        latch.await();
        System.out.println("线程:"+Thread.currentThread().getName()+" 使用时间:"+(System.currentTimeMillis()-start)+"ms");
    }

    private static void handler() {
        int result = Compute.fibo(7);
        System.out.println("线程:"+Thread.currentThread().getName()+" 异步计算结果:"+result);
    }

执行结果:

android 子线程阻塞后如何结束 子线程阻塞主线程_java_06

方式七:LockSupport.park和unpark

public static void main(String[] args) {

        long start = System.currentTimeMillis();
        Thread mainThread = Thread.currentThread();
        //异步执行
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                handler(mainThread);
            }
        });
        t.start();
        LockSupport.park(mainThread);
        System.out.println("线程:"+Thread.currentThread().getName()+" 使用时间:"+(System.currentTimeMillis()-start)+"ms");
    }

    private static void handler(Thread mainThread) {
        int result = Compute.fibo(7);
        System.out.println("线程:"+Thread.currentThread().getName()+" 异步计算结果:"+result);
        LockSupport.unpark(mainThread);
    }

执行结果:

android 子线程阻塞后如何结束 子线程阻塞主线程_thread_07

方式八:LockSupport.parkNanos 超时时间

public static void main(String[] args) {

        long start = System.currentTimeMillis();
        Thread mainThread = Thread.currentThread();
        //异步执行
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                handler();
            }
        });
        t.start();
        LockSupport.parkNanos(mainThread, 100L);
        System.out.println("线程:"+Thread.currentThread().getName()+" 使用时间:"+(System.currentTimeMillis()-start)+"ms");
    }

    private static void handler() {
        int result = Compute.fibo(7);
        System.out.println("线程:"+Thread.currentThread().getName()+" 异步计算结果:"+result);
    }

执行结果:

android 子线程阻塞后如何结束 子线程阻塞主线程_thread_08

方式九:LockSupport.parkUntil 截止到某时间点释放方式

public static void main(String[] args) {
        long start = System.currentTimeMillis();
        Thread mainThread = Thread.currentThread();
        //异步执行
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                handler();
            }
        });
        t.start();
        LockSupport.parkUntil(mainThread, System.currentTimeMillis()+1000);
        System.out.println("线程:"+Thread.currentThread().getName()+" 使用时间:"+(System.currentTimeMillis()-start)+"ms");
    }

    private static void handler() {
        int result = Compute.fibo(7);
        System.out.println("线程:"+Thread.currentThread().getName()+" 异步计算结果:"+result);
    }

执行结果:

android 子线程阻塞后如何结束 子线程阻塞主线程_多线程_09

方式十:CountDownLatch.await(long t, TimeUtil t)

public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(1);

        long start = System.currentTimeMillis();
        //异步执行
        new Thread(() -> {
            handler();
        }).start();

        latch.await(100, TimeUnit.MILLISECONDS);
        System.out.println("线程:"+Thread.currentThread().getName()+" 使用时间:"+(System.currentTimeMillis()-start)+"ms");
    }

    private static void handler() {
        int result = Compute.fibo(7);
        System.out.println("线程:"+Thread.currentThread().getName()+" 异步计算结果:"+result);
    }

执行结果:

android 子线程阻塞后如何结束 子线程阻塞主线程_java_10

方式十一:ExecutorService.submit+Future.get()阻塞 线程池

public static void main(String[] args) {

        long start = System.currentTimeMillis();
        ExecutorService executorService = new ThreadPoolExecutor(2,2,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<>());
        Future<Integer> future = executorService.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                return handler();
            }
        });

        try {
            System.out.println("异步线程输出结果:"+future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        executorService.shutdown();
        System.out.println("线程:"+Thread.currentThread().getName()+" 使用时间:"+(System.currentTimeMillis()-start)+"ms");
    }

    private static int handler() {
        int result = Compute.fibo(7);
        System.out.println("线程:"+Thread.currentThread().getName()+" 异步计算结果:"+result);
        return result;
    }

执行结果:

android 子线程阻塞后如何结束 子线程阻塞主线程_System_11

方式十二:线程池+synchronized  方式,下面要么同时锁住oo,要么同时锁住mainThread,效果一样

public static void main(String[] args) {
        Object oo = new Object();
        Thread mainThread = Thread.currentThread();
        long start = System.currentTimeMillis();
        ExecutorService executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                60L, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>());
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                handler(oo, mainThread);
            }
        });
        executorService.shutdown();
        synchronized (mainThread){
            try {
                mainThread.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("线程:"+Thread.currentThread().getName()+" 使用时间:"+(System.currentTimeMillis()-start)+"ms");
    }

    private static int handler(Object oo, Thread mainThread) {
        int result = Compute.fibo(7);
        System.out.println("线程:"+Thread.currentThread().getName()+" 异步计算结果:"+result);
        synchronized (mainThread){
            mainThread.notify();
        }
        return result;
    }

执行结果:

android 子线程阻塞后如何结束 子线程阻塞主线程_System_12

方式十三:FutureTask+异步线程启动+future.get()阻塞

public static void main(String[] args) {

        long start = System.currentTimeMillis();
        FutureTask<Integer> futureTask = new FutureTask<>(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                return handler();
            }
        });
        //异步启动
        new Thread(futureTask).start();
        try {
            System.out.println("异步线程输出结果:"+futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println("线程:"+Thread.currentThread().getName()+" 使用时间:"+(System.currentTimeMillis()-start)+"ms");
    }

    private static int handler() {
        int result = Compute.fibo(7);
        System.out.println("线程:"+Thread.currentThread().getName()+" 异步计算结果:"+result);
        return result;
    }

执行结果:

android 子线程阻塞后如何结束 子线程阻塞主线程_java_13

方式十四:CompletableFuture.supplyAsync()  ,分为指定线程池和默认线程池两种

public static void main(String[] args) throws ExecutionException, InterruptedException {
        long start = System.currentTimeMillis();

        //如果不指定线程池默认使用ForkJoinPool.commonPool()
//        CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
//            return handler();
//        });

        //也可以指定线程池
        ExecutorService executorService = new ThreadPoolExecutor(2,2,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<>());
        CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return handler();
        }, executorService);

        System.out.println("异步输出结果:"+integerCompletableFuture.get());
        //如果指定了线程池得关闭
        executorService.shutdown();
        System.out.println("线程:"+Thread.currentThread().getName()+" 使用时间:"+(System.currentTimeMillis()-start)+"ms");
    }

    private static int handler() {
        int result = Compute.fibo(7);
        System.out.println("线程:"+Thread.currentThread().getName()+" 异步计算结果:"+result);
        return result;
    }

执行结果:

android 子线程阻塞后如何结束 子线程阻塞主线程_多线程_14

方式十五:CompletableFuture.runAsync()  ,分为指定线程池和默认线程池两种

public static void main(String[] args) throws ExecutionException, InterruptedException {
        long start = System.currentTimeMillis();

        //如果不指定线程池默认使用ForkJoinPool.commonPool()
        CompletableFuture<Void> integerCompletableFuture = CompletableFuture.runAsync(() -> {
            handler();
        });

        //也可以指定线程池
//        ExecutorService executorService = new ThreadPoolExecutor(2,2,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<>());
//        CompletableFuture<Void> integerCompletableFuture = CompletableFuture.runAsync(() -> {
//            handler();
//        }, executorService);

        //runAsync没有返回值,输出为null
        System.out.println("异步输出结果:"+integerCompletableFuture.get());
        //如果指定了线程池得关闭
//        executorService.shutdown();
        System.out.println("线程:"+Thread.currentThread().getName()+" 使用时间:"+(System.currentTimeMillis()-start)+"ms");
    }

    private static int handler() {
        int result = Compute.fibo(7);
        System.out.println("线程:"+Thread.currentThread().getName()+" 异步计算结果:"+result);
        return result;
    }

执行结果:

android 子线程阻塞后如何结束 子线程阻塞主线程_java_15