JAVA多线程-Main 函数在子 thred 执行完之前就结束了

WHAT

今天测试一个多线程代码。简单来说,就是在 Main 函数里,创建了一个 长度为 1500 的数组,并使用了如下代码:

    Thread thread = new Thread(()->{
		while (!list.isEmpty()){
			tasks.get(0);
			System.out.println(list.size());
			tasks.remove(list.get(0));
		 }
        });
    thread.start();

代码很简单,就是 thred 循环 list。但是,发现这样子跑的结果是:
数字远远不到1500就没有了!
image
怎么会这样子呢!

Why

仔细观察,在 exit 之后,还有一句打印,是不是说明,子线程其实没有结束,只是控制台进程结束了,看不到打印了!而且,程序也没有发生异常。
image

顺着这个思路百度,原来,Main 函数自己跑完之后,就不会管其他线程了,直接结束了。因此控制台的输出自然也结束了。我们的 Thred 其实并没有结束。这里涉及到守护进程的概念。默认创建的子线程都是非守护进程。Main 函数并不会管这些进程的死活,自己先结束了。

How

那么,怎么可以让 Main 线程等待子线程呢?很简单,Thread.sleep(10000) 就搞定了!但是这样子显然不是好的方法!

这里使用 CountDownLatch 可以操作。
我们先看代码:

    final CountDownLatch countDownLatch = new CountDownLatch(1);
	
    Thread thread = new Thread(()->{
		while (!list.isEmpty()){
			tasks.get(0);
			System.out.println(list.size());
			tasks.remove(list.get(0));
		 }
		countDownLatch.countDown();
        });
		
    thread.start();
  countDownLatch.await();

首先,我们定义了一个 CountDownLatch 类,这个类初始化,可以传进去一个数字,这个数字就是计数器。
当调用 countDownLatch.countDown() 时,这个计数器就会减一。

countDownLatch.await() 则会阻塞调用这一语句的线程,直到计数器到 0,这里阻塞的也就是 Main 函数。

很明显,countDownLatch.countDown() 放在执行完循环 list 之后,此时计数器才会从1减为0,那么 Main 就会等到 thread 循环完毕之后才会结束。

这样子,我们再看控制台,可以完整打印到1500了!
image

posted @ 2022-06-15 18:15  快乐的海盗  阅读(663)  评论(0编辑  收藏  举报