线程中的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

import org.junit.Test;

/**
 * @Author xpf
 * @Date 2023/9/5 17:07
 * @Version 1.0
 *  要求线程a执行完才开始线程b, 线程b执行完才开始线程c
 */
public class MyThreadJoin {

    public static class MyThread extends Thread{

        MyThread(String name){
            super(name);
        }

        @Override
        public void run() {
            for (int i= 1; i <= 10; i++){
                System.out.println(getName() + ":" + i);
            }
        }
    }

    //https://blog.csdn.net/shinecjj/article/details/103792151
    public static void main(String[] args) {
        MyThread t1 = new MyThread("a");
        MyThread t2 = new MyThread("b");
        MyThread t3 = new MyThread("c");

        try {
            t1.start();
            t1.join();

            t2.start();
            t2.join();

            t3.start();
            t3.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


}

结果:

二、wait() 和 notify()

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

2、wait():

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

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

 3、notify():

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

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

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

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

/**
 * @Author xpf
 * @Date 2023/9/6 10:35
 * @Version 1.0
 * 2、两个线程轮流打印数字,一直到100
 * wait() 和 notify() 是object对象的方法
 * wait():可以使当前线程进入等待状态,直到其他线程调用 notify() 或者 notifyAll() 方法唤醒它。
 *         在调用 wait() 方法时,当前线程会释放它所持有的锁,以便其他线程可以访问共享资源
 * notify():用于唤醒一个处于等待状态的线程,如果有多个线程在等待,则只会唤醒其中一个线程。notifyAll方法则会唤醒所有处于等待状态的线程。
 * wait和 notify 方法必须在同步块中使用,即在使用这两个方法的对象上获取锁。否则会抛出illegalMonitorStateException异常
 */
public class ThreadWaitNotify {

     static class TakeTurnsAdd{
        final Object lock = new Object();
        boolean getFlag = true;
        int sum = 1;
        public void add1(){
            synchronized (lock){
                String threadName = Thread.currentThread().getName();
                for (int i = 1; i <= 50; i++) {
                    if (getFlag){
                        try {
//                            System.out.println(threadName + "wait()前" );
                            lock.wait();
//                            System.out.println(threadName + "wait()后" );
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                    }

                    System.out.println(threadName + "a:" + sum++);
//                    System.out.println(threadName + "notify()前" );
                    getFlag = !getFlag;
                    lock.notify();
//                    System.out.println(threadName + "notify()后" );
                }
            }

        }

        public void add2(){
            synchronized (lock){
                String threadName = Thread.currentThread().getName();
                for (int i = 1; i <= 50; i++) {
                    if (!getFlag){
                        try {
//                            System.out.println(threadName + "wait()前" );
                            lock.wait();
//                            System.out.println(threadName + "wait()后" );
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(threadName + "b:" + sum++);
//                    System.out.println(threadName + "notify()前" );
                    getFlag = !getFlag;
                    lock.notify();
//                    System.out.println(threadName + "notify()后" );
                }
            }

        }
    }

    public static void main(String[] args) {
        TakeTurnsAdd takeTurnsAdd = new TakeTurnsAdd();
        new Thread(()->{takeTurnsAdd.add1();}).start();
        new Thread(()->{takeTurnsAdd.add2();}).start();
    }
}

结果:

...

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

/**
 * @Author xpf
 * @Date 2023/9/6 10:35
 * @Version 1.0
 * 两线程,一个打印数字从1到52,另一个打印字母从A到Z,输出:12A34B56C...5152Z
 */
public class ThreadWaitNotify2 {

     static class TakeTurnsAdd{
        final Object lock = new Object();
        boolean getFlag = false;
        int sum = 1;
        public void add1(){
            synchronized (lock){
                String threadName = Thread.currentThread().getName();
                for (int i = 1; i <= 26; i++) {
                    if (getFlag){
                        try {
//                            System.out.println(threadName + "wait()前" );
                            lock.wait();
//                            System.out.println(threadName + "wait()后" );
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                    }
                    System.out.print(sum++);
                    System.out.print(sum++);
//                    System.out.println(threadName + "notify()前" );
                    getFlag = !getFlag;
                    lock.notify();
//                    System.out.println(threadName + "notify()后" );
                }
            }

        }

        public void add2(){
            synchronized (lock){
                String threadName = Thread.currentThread().getName();
                for (int i = 0; i < 26; i++) {
                    if (!getFlag){
                        try {
//                            System.out.println(threadName + "wait()前" );
                            lock.wait();
//                            System.out.println(threadName + "wait()后" );
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.print((char) (65+i));
//                    System.out.println(threadName + "notify()前" );
                    getFlag = !getFlag;
                    lock.notify();
//                    System.out.println(threadName + "notify()后" );
                }
            }

        }
    }

    public static void main(String[] args) {
        TakeTurnsAdd takeTurnsAdd = new TakeTurnsAdd();
        new Thread(()->{takeTurnsAdd.add1();}).start();
        new Thread(()->{takeTurnsAdd.add2();}).start();
    }
}

结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值