多线程等待所有子线程执行完使用总结——wait()和notify(),join()方法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程等待所有子线程执行完使用总结——wait()和notify(),join()方法相关的知识,希望对你有一定的参考价值。

多线程等待所有子线程执行完使用总结(1)——wait()和notify(),join()方法

问题背景

我们在日常开发和学习过程中,经常会使用到多线程的场景,其中我们经常会碰到,我们代码需要等待某个或者多个线程执行完再开始执行,那么这种场景可以有多少方法实现呢?本文就对这个场景的解决方案进行初步的介绍。

问题分析

1、Object的wait()和notify()方法

等待(wait):一个线程因为执行某个操作所需的保护条件未满足而被暂停的过程。 通知(notify):一个线程更新了共享变量,使得其他线程需要的保护条件成立,唤醒了被暂停的线程的过程。 wait()方法的执行线程叫等待线程,notify()方法执行的线程叫通知线程。 demo代码如下:

package composer

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import java.lang.Thread.sleep

class TestWaitActivity : AppCompatActivity() 
    private val lockObject = Object()

    companion object 
        const val TAG = "TestWaitActivity"
    

    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test_wait)

        Log.d(TAG, "onCreate begin")

        val threadWait = WaitThread()
        threadWait.start()

        // 获取当前系统时间
        val beginTime = System.currentTimeMillis()

        synchronized(lockObject) 
            try 
                Log.d(TAG, "主线程开始等待")
                lockObject.wait()
             catch (e: InterruptedException) 
                e.printStackTrace()
            
        
        Log.d(TAG, "耗时:" + (System.currentTimeMillis() - beginTime))
    

    inner class WaitThread: Thread() 
        override fun run() 
            Log.d(TAG, "WaitThread run begin")
            synchronized (lockObject) 
                try 
                    Log.d(TAG, "WaitThread synchronized")
                    // 模拟耗时任务
                    sleep(3000)
                    lockObject.notify()

                 catch (e: InterruptedException) 
                    e.printStackTrace();
                

            
        
    

运行结果如下: 运行结果分析: wait()方法可以使当前线程A马上失去对象锁并且沉睡,直到对象调用notify()唤醒该线程。此时持有对象锁的线程会先行执行完毕,然后再将对象锁交给沉睡的线程继续执行。

2、线程的join()方法

thread.join()把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,那么要等线程A执行完毕后,才会继续执行线程B。demo代码如下:

fun main() 
    val thread1 = Thread 
        run 
            println("i am thread1")
            // 模拟耗时任务
            Thread.sleep(2000)
            println("i am thread1 sleep ok")
        
    

    val thread2 = Thread 
        run 
            thread1.join()
            println("i am thread2")
        
    
    thread1.start()

    thread2.start()

运行结果如下: 运行结果分析: 线程2的run()方法中调用thread1.join(),这个位置会等thread1执行完才会继续去执行线程2中的代码。 这里也可以看下Thread类join的源码也比较容易理解: (1)java.lang.Thread#join()

    /**
     * Waits for this thread to die.
     *
     * <p> An invocation of this method behaves in exactly the same
     * way as the invocation
     *
     * <blockquote>
     * @linkplain #join(long) join@code (0)
     * </blockquote>
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    public final void join() throws InterruptedException 
        join(0);
    

(2)java.lang.Thread#join(long)

    public final void join(long millis)
    throws InterruptedException 
        synchronized(lock) 
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) 
            throw new IllegalArgumentException("timeout value is negative");
        

        if (millis == 0) 
            while (isAlive()) 
                lock.wait(0);
            
         else 
            while (isAlive()) 
                long delay = millis - now;
                if (delay <= 0) 
                    break;
                
                // 通过Object对象的wait方法,进行一个延迟时间的等待
                lock.wait(delay);
                now = System.currentTimeMillis() - base;
            
        
        
    

问题总结

本文主要介绍了等待线程结束再执行的两个方案,(1)Object的wait()和notify()方法,(2)线程的join()方法,后面会继续介绍CountDownLatch类、CyclicBarrier类和自定义个一个原子类型计数器的方法,有兴趣的同学可以进一步深入研究。

以上是关于多线程等待所有子线程执行完使用总结——wait()和notify(),join()方法的主要内容,如果未能解决你的问题,请参考以下文章

多线程等待所有子线程执行完使用总结——CyclicBarrier使用和源码初步分析

java 多线程 , 等待所有子线程都执行完后 , 在执行主线程(其中的一种 , 也是个人觉得最好用的一种)

如何使“主线程”等待“子线程”执行结束后再继续执行

java多线程16:join()的使用

java多线程wait notify join

多线程开发关键技术