暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Java#主线程等待子线程执行

小怂读书 2021-10-21
612

主线程开启子线程执行任务后,主线程hang住,等待子线程执行完成后再继续执行。

梳理具体的实现方法:

1、CountDownLaunch实现

子程序执行完成后,launch--。

private static void caseByCountDownLaunch() {
        CountDownLatch countDownLatch = new CountDownLatch(2);
new Thread(() -> {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
System.out.println(System.currentTimeMillis() + " 线程1执行完成。");
}).start();


new Thread(() -> {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
System.out.println(System.currentTimeMillis() + " 线程2执行完成。");
}).start();
System.out.println(System.currentTimeMillis() + " 主线程执行到这里了");
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + " 主线程执行完");

复制


2、Thread.join方法

官方文档解释:主线程的代码块中遇到join()方法时,主线程需要等待子线程结束了(Waits for this thread to die.),才能继续执行join()之后的代码块。

/**
* Thread.join()
*/
private static void caseByThreadJoin() {
Thread t1 = new Thread(new Runnable() {
@Override
            public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + " 线程1执行完成。");
}
});


Thread t2 = new Thread(new Runnable() {
@Override
            public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + " 线程2执行完成。");
}
});
System.out.println(System.currentTimeMillis() + " 主线程执行到这里了");
try {
t1.start();
t2.start();
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + " 主线程执行完");
    }
复制


3、ThreadPool#isTerminal

判断线程池中线程是否都执行完了,都执行完后,主线程执行。

private static void caseByThreadPoolIsTerminal() {
ExecutorService pool = Executors.newFixedThreadPool(2);
pool.execute(new Thread(new Runnable() {
@Override
            public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + " 线程1执行完成。");
}
}));
pool.execute(new Thread(new Runnable() {
@Override
            public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + " 线程2执行完成。");
}
}));
pool.shutdown(); //不关闭的情况,线程池会一直开启,等待
System.out.println(System.currentTimeMillis() + " 主线程执行到这里了");
while (!pool.isTerminated()) {
System.out.println("主线程等待");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(System.currentTimeMillis() + " 主线程执行完");
}
复制


4、Future

Future.get()阻塞,主线程实现等待。

private static void caseByFuture() {
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<Integer> f1 = pool.submit(new Callable<Integer>() {
@Override
            public Integer call() throws Exception {
Thread.sleep(3000);
System.out.println(System.currentTimeMillis() + " 线程1执行完成");
return 1;
}
});
Future<Integer> f2 = pool.submit(new Callable<Integer>() {
@Override
            public Integer call() throws Exception {
Thread.sleep(3000);
System.out.println(System.currentTimeMillis() + " 线程2执行完成");
return 1;
}
});
pool.shutdown(); //不关闭用户线程,jvm一直在等待
System.out.println(System.currentTimeMillis() + " 主线程执行到这里了");
try {
f1.get();
f2.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + " 主线程执行完");
}
复制


5、CompletableFuture同上

private static void caseByCompletableFuture() {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
            public Integer get() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " " + System.currentTimeMillis() + " 线程1执行到这里");
return 1;
}
});
System.out.println(Thread.currentThread().getName() + " " + System.currentTimeMillis() + " 主线程执行到这里了");
future.join();
System.out.println(Thread.currentThread().getName() + " " + System.currentTimeMillis() + " 主线程执行完");
}
复制


6、CyclicBarrier方式

/**
* 通过CyclicBarrier实现
* CyclicBarrier 基于Condition来实现的。在CyclicBarrier类的内部有一个计数器,每个线程在到达屏障点的时候都会调用await方法将自己阻塞,此时计数器会减1,当计数器减为0的时候所有因调用await方法而被阻塞的线程将被唤醒。这就是实现一组线程相互等待的原理。
* CountDownLatch是线程组之间的等待,即一个(或多个)线程等待N个线程完成某件事情之后再执行;而CyclicBarrier则是线程组内的等待,即每个线程相互等待,即N个线程都被拦截之后,然后依次执行。
* CountDownLatch是减计数方式,而CyclicBarrier是加计数方式。
* CountDownLatch计数为0无法重置,而CyclicBarrier计数达到初始值,则可以重置。
* CountDownLatch不可以复用,而CyclicBarrier可以复用。
*/
private static void caseByCyclicBarrier() {
CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
new Thread(new Runnable() {
    @Override
    public void run() {
try {
Thread.sleep(3000);
cyclicBarrier.await();
} catch (InterruptedException e) {
            e.printStackTrace();
} catch (BrokenBarrierException e) {
         e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName() + " " + System.currentTimeMillis() + " 线程1执行完成。");
   }
   }).start();
   new Thread(new Runnable() {
@Override
            public void run(){
try {
Thread.sleep(6000);
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " " + System.currentTimeMillis() + " 线程2执行完成。");
}
}).start();
System.out.println(Thread.currentThread().getName() + " " + System.currentTimeMillis() + " 主线程执行到这里了");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " " + System.currentTimeMillis() + " 主线程执行完");
    }
复制


7、Thread#isAlive实现

private static void caseByThreadIsAlive() {
new Thread(new Runnable() {
@Override
            public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + System.currentTimeMillis() + " 线程1执行完成。");
}
}).start();


new Thread(new Runnable() {
@Override
            public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + " 线程2执行完成。");
}
}).start();
System.out.println(Thread.currentThread().getName() + System.currentTimeMillis() + " 主线程执行到这里了");
while (Thread.activeCount() > 2) {
System.out.println("Thread.activeCount()=" + Thread.activeCount());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 主线程等待");
}
System.out.println(Thread.currentThread().getName() + System.currentTimeMillis() + " 主线程执行完");
}
复制


8、并发锁、同步控制等方式

private static void caseByAtomicInteger() {
AtomicInteger atomicInteger = new AtomicInteger(2);
new Thread(new Runnable() {
@Override
            public void run() {
try {
Thread.sleep(3000);
atomicInteger.decrementAndGet();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + System.currentTimeMillis() + " 线程1执行完成。");
}
}).start();


new Thread(new Runnable() {
@Override
            public void run() {
try {
Thread.sleep(3000);
atomicInteger.decrementAndGet();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + " 线程2执行完成。");
}
}).start();
System.out.println(Thread.currentThread().getName() + System.currentTimeMillis() + " 主线程执行到这里了");
while (atomicInteger.get() != 0) {
System.out.println("Thread.activeCount()=" + Thread.activeCount());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 主线程等待");
}
System.out.println(Thread.currentThread().getName() + System.currentTimeMillis() + " 主线程执行完");
}
复制


文章转载自小怂读书,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论