• 线程中的join()、wait() 和 notify()详解及练习题


    一、join()

    Thread提供了 join() 方法,用于等待当前线程所调用的其他线程执行完毕。

    1、当一个线程调用另一个线程的 join() 方法时,它会被阻塞,直到被调用的线程执行完毕或达到指定的超时时间。

    比如:当主线程main中调用了另一个线程thread1,那么main线程会被阻塞,只有当thread1执行完毕,main线程才继续执行。

    2、当然也可以调用join() 方法还有一个重载的形式,允许指定等待的最大时间:

    public final synchronized void join(long millis) throws InterruptedException

    在上述形式中,millis 参数表示等待的最大时间,以毫秒为单位。如果被调用的线程在指定的时间内没有执行完毕,当前线程将不再等待,继续执行后续的操作。

    join() 方法通常用于实现线程之间的协作和同步。例如,可以创建多个线程,然后使用 join() 方法来确保这些线程按照特定的顺序执行。

    练习1:要求线程a执行完才开始线程b, 线程b执行完才开始线程c

    1. import org.junit.Test;
    2. /**
    3. * @Author xpf
    4. * @Date 2023/9/5 17:07
    5. * @Version 1.0
    6. * 要求线程a执行完才开始线程b, 线程b执行完才开始线程c
    7. */
    8. public class MyThreadJoin {
    9. public static class MyThread extends Thread{
    10. MyThread(String name){
    11. super(name);
    12. }
    13. @Override
    14. public void run() {
    15. for (int i= 1; i <= 10; i++){
    16. System.out.println(getName() + ":" + i);
    17. }
    18. }
    19. }
    20. //https://blog.csdn.net/shinecjj/article/details/103792151
    21. public static void main(String[] args) {
    22. MyThread t1 = new MyThread("a");
    23. MyThread t2 = new MyThread("b");
    24. MyThread t3 = new MyThread("c");
    25. try {
    26. t1.start();
    27. t1.join();
    28. t2.start();
    29. t2.join();
    30. t3.start();
    31. t3.join();
    32. } catch (InterruptedException e) {
    33. e.printStackTrace();
    34. }
    35. }
    36. }

    结果:

    二、wait() 和 notify()

    1、wait() 和 notify() 是object对象的方法

    2、wait():

    可以使当前线程进入等待状态直到其他线程调用 notify() 或者 notifyAll() 方法唤醒它。

    在调用 wait() 方法时,当前线程会释放它所持有的锁,以便其他线程可以访问共享资源

     3、notify():

    用于唤醒一个处于等待状态的线程,如果有多个线程在等待,则只会唤醒其中一个线程

    notifyAll() 方法则会唤醒所有处于等待状态的线程。 

    wait和 notify 方法必须在同步块中使用,即在使用这两个方法的对象上获取锁。否则会抛出illegalMonitorStateException异常

    练习1:两个线程轮流打印数字,一直到100

    1. /**
    2. * @Author xpf
    3. * @Date 2023/9/6 10:35
    4. * @Version 1.0
    5. * 2、两个线程轮流打印数字,一直到100
    6. * wait() 和 notify() 是object对象的方法
    7. * wait():可以使当前线程进入等待状态,直到其他线程调用 notify() 或者 notifyAll() 方法唤醒它。
    8. * 在调用 wait() 方法时,当前线程会释放它所持有的锁,以便其他线程可以访问共享资源
    9. * notify():用于唤醒一个处于等待状态的线程,如果有多个线程在等待,则只会唤醒其中一个线程。notifyAll方法则会唤醒所有处于等待状态的线程。
    10. * wait和 notify 方法必须在同步块中使用,即在使用这两个方法的对象上获取锁。否则会抛出illegalMonitorStateException异常
    11. */
    12. public class ThreadWaitNotify {
    13. static class TakeTurnsAdd{
    14. final Object lock = new Object();
    15. boolean getFlag = true;
    16. int sum = 1;
    17. public void add1(){
    18. synchronized (lock){
    19. String threadName = Thread.currentThread().getName();
    20. for (int i = 1; i <= 50; i++) {
    21. if (getFlag){
    22. try {
    23. // System.out.println(threadName + "wait()前" );
    24. lock.wait();
    25. // System.out.println(threadName + "wait()后" );
    26. } catch (InterruptedException e) {
    27. e.printStackTrace();
    28. }
    29. }
    30. System.out.println(threadName + "a:" + sum++);
    31. // System.out.println(threadName + "notify()前" );
    32. getFlag = !getFlag;
    33. lock.notify();
    34. // System.out.println(threadName + "notify()后" );
    35. }
    36. }
    37. }
    38. public void add2(){
    39. synchronized (lock){
    40. String threadName = Thread.currentThread().getName();
    41. for (int i = 1; i <= 50; i++) {
    42. if (!getFlag){
    43. try {
    44. // System.out.println(threadName + "wait()前" );
    45. lock.wait();
    46. // System.out.println(threadName + "wait()后" );
    47. } catch (InterruptedException e) {
    48. e.printStackTrace();
    49. }
    50. }
    51. System.out.println(threadName + "b:" + sum++);
    52. // System.out.println(threadName + "notify()前" );
    53. getFlag = !getFlag;
    54. lock.notify();
    55. // System.out.println(threadName + "notify()后" );
    56. }
    57. }
    58. }
    59. }
    60. public static void main(String[] args) {
    61. TakeTurnsAdd takeTurnsAdd = new TakeTurnsAdd();
    62. new Thread(()->{takeTurnsAdd.add1();}).start();
    63. new Thread(()->{takeTurnsAdd.add2();}).start();
    64. }
    65. }

    结果:

    ...

     练习2:两线程,一个打印数字从1到52,另一个打印字母从A到Z,输出:12A34B56C...5152Z

    1. /**
    2. * @Author xpf
    3. * @Date 2023/9/6 10:35
    4. * @Version 1.0
    5. * 两线程,一个打印数字从1到52,另一个打印字母从A到Z,输出:12A34B56C...5152Z
    6. */
    7. public class ThreadWaitNotify2 {
    8. static class TakeTurnsAdd{
    9. final Object lock = new Object();
    10. boolean getFlag = false;
    11. int sum = 1;
    12. public void add1(){
    13. synchronized (lock){
    14. String threadName = Thread.currentThread().getName();
    15. for (int i = 1; i <= 26; i++) {
    16. if (getFlag){
    17. try {
    18. // System.out.println(threadName + "wait()前" );
    19. lock.wait();
    20. // System.out.println(threadName + "wait()后" );
    21. } catch (InterruptedException e) {
    22. e.printStackTrace();
    23. }
    24. }
    25. System.out.print(sum++);
    26. System.out.print(sum++);
    27. // System.out.println(threadName + "notify()前" );
    28. getFlag = !getFlag;
    29. lock.notify();
    30. // System.out.println(threadName + "notify()后" );
    31. }
    32. }
    33. }
    34. public void add2(){
    35. synchronized (lock){
    36. String threadName = Thread.currentThread().getName();
    37. for (int i = 0; i < 26; i++) {
    38. if (!getFlag){
    39. try {
    40. // System.out.println(threadName + "wait()前" );
    41. lock.wait();
    42. // System.out.println(threadName + "wait()后" );
    43. } catch (InterruptedException e) {
    44. e.printStackTrace();
    45. }
    46. }
    47. System.out.print((char) (65+i));
    48. // System.out.println(threadName + "notify()前" );
    49. getFlag = !getFlag;
    50. lock.notify();
    51. // System.out.println(threadName + "notify()后" );
    52. }
    53. }
    54. }
    55. }
    56. public static void main(String[] args) {
    57. TakeTurnsAdd takeTurnsAdd = new TakeTurnsAdd();
    58. new Thread(()->{takeTurnsAdd.add1();}).start();
    59. new Thread(()->{takeTurnsAdd.add2();}).start();
    60. }
    61. }

    结果:

  • 相关阅读:
    通过API接口实现数据实时更新的方案(InsCode AI 创作助手)
    Effective C++ 笔记
    Automatic differentiation package - torch.autograd
    hashmap的一些坑
    hardhat 教程及 hardhat-deploy 插件使用
    使用AWK进行文本处理
    〔025〕Stable Diffusion 之 接口开发 篇
    牛客网Verilog刷题 | 快速入门-基础语法
    Android 应用启动过程优化
    2022最新解析最清晰 Java 系列面试题
  • 原文地址:https://blog.csdn.net/qq_44299529/article/details/132719461