在一个开源项目中,有一个录音功能,录音是在一个子线程中完成的,当调用停止录音时,执行的函数如下:
- public void stopRecordThread() {
- if (recordThread != null) {
- try {
- recordThread.join();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- recordThread = null;
- }
- }
-
查看了JDK文档,join()函数的功能是:等待该线程终止。如上代码,我们调用录音线程的join函数,则是等待录音线程终止,也就是说,如果录音线程没执行完,stopRecord()函数就一直等在那里,是一个阻塞状态,写个示例代码演示如下:
- public class Main {
-
- public static void main(String[] args) {
- Thread thread = new Thread(Main::printInfo, "Thread");
- thread.start();
- printInfo();
- }
-
- public static void printInfo() {
- try {
- String name = Thread.currentThread().getName();
- for (int i = 1; i <= 5; i++) {
- System.out.println(name + " " + i);
- Thread.sleep(1000);
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
-
这里有两个线程都调用了printInfo函数,一个是子线程,一个是主线程,printInfo函数的功能是打印5条信息,每条信息打印了线程名称和序号,每打印一条信息后就睡眠1秒钟,执行效果如下:
- main 1
- Thread 1
- Thread 2
- main 2
- Thread 3
- main 3
- main 4
- Thread 4
- main 5
- Thread 5
-
可以看到两个线程同时进行,如果我们希望子线程执行结束之后,再来执行主线程,只需要调用子线程的join函数即可实现,代码如下:
- public static void main(String[] args) throws InterruptedException {
- Thread threadA = new Thread(Main::printInfo, "Thread");
- threadA.start();
- threadA.join();
- printInfo();
- }
-
执行效果如下:
- Thread 1
- Thread 2
- Thread 3
- Thread 4
- Thread 5
- main 1
- main 2
- main 3
- main 4
- main 5
-
可以看到,调用了join()函数后,主线程就被阻塞了,不再往下执行,直到子线程执行结束后再往下执行。
回到文章的开头,一个录音线程,在调用录音Api的停止函数后,系统就不再给出录音数据了,但是录音线程可能还在写录音数据呢,所以要等录音线程执行完毕,不能直接中止录音线程,所以调用了join函数来实现。
后续:子线程执行完之后,子线程自己不就结束了吗?为什么需要调用一个join去把自己阻塞了呢?而且我们看到它调用join()的后面也没写别的代码。我猜啊,这个stopRecordThread()函数是一个回调函数,在别处调用这个函数,则在别处自然就会阻塞住了,所以阻塞之后做了什么就要看是什么地方调用了这个函数。我在这个函数上打印了一下线程名称,发现调用stopRecordThread()函数的函数也是在子线程上运行的,所以虽然阻塞了,但阻塞的是一个子线程,所以不用担心主线程。