并发编程-线程调度-park、unpark、join、wait、notify

1.park、unpark概念及使用

1.1概念

 在Java并发编程中,park和unpark是LockSupport类提供的两个静态方法,用于线程的阻塞和解除阻塞。‌

park方法用于阻塞当前线程,使其进入等待状态,而unpark方法用于解除被park方法阻塞的线程。这两个方法通常用于实现线程间的同步和通信, 可以替代传统的wait和notify机制,提供更灵活的方式来控制线程的阻塞和唤醒‌。

park方法的使用

当线程调用park方法时,它会阻塞当前线程,直到以下情况之一发生:

1.另一个线程调用了相应线程的unpark方法;

2.中断发生;

3.在被禁用的情况下调用park,并且在调用unpark之前已经有了许可;

*park方法可以重载,提供不同的版本,如parkNanos和parkUntil,以支持 超时 和 特定时间点 的阻塞‌。

unpark方法的使用:unpark方法用于解除被park方法阻塞的线程。

1..如果给定线程尚未被阻塞,调用 unpark 方法将设置该线程的许可,这样后续对park的调用将立即返回;

2.如果给定线程已经被park,则调用 unpark 将使其解除阻塞。

1.2Demo

public class parkDemo01 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " 开始执行");
                LockSupport.park();// 阻塞当前线程
                System.out.println(Thread.currentThread().getName() + " 执行完成");
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " 开始执行");
                System.out.println(Thread.currentThread().getName() + " 执行完成");
            }
        });
        thread1.start();
        thread2.start();

        Thread.sleep(3000);// 等待 thread2 的完成
        System.out.println("主线程 唤醒 thread1");
        LockSupport.unpark(thread1);// unpark 唤醒 thread1

        thread1.join();// 等待thread1的完成
        System.out.println("主线程 执行");
    }
}

1.3执行结果

Thread-1成功执行;Thread-0在启动后调用park方法阻塞,待主线程唤醒后,Thread-0继续执行。

2.join概念及使用

2.1概念

join()方法用于等待调用该方法的线程完成执行。当一个线程调用另一个线程的join()方法时,它会暂停自己的执行,直到被调用的线程完成执行才会继续执行

join()方法特点:
1.等待线程完成:调用join()方法的线程会等待被调用的线程完成执行。这在需要等待其他线程完成某个任务后再继续执行的情况下非常有用。
2.同步操作:通过join()方法,可以实现线程的同步操作。主线程可以调用子线程的join()方法,确保子线程在完成后再继续执行主线程的后续操作。
3.协调线程顺序:通过多次调用join()方法,可以协调多个线程的执行顺序,确保它们按照特定的顺序执行。
4.异常处理:如果被调用的线程抛出了未捕获的异常,调用它的线程可以通过捕获该异常来处理或做出相应的操作。

2.2Demo

public class JoinDemo01 {
    public static void main(String[] args) throws InterruptedException {
        // 线程的总体执行顺序: thread1 -> thread2 -> thread3
        Thread thread1 = new Thread(() -> {
            System.out.println("线程1执行了");
        });

        Thread thread2 = new Thread(() -> {
            try {
                thread1.join();// thread1 -> thread2
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("线程2执行了");
        });

        Thread thread3 = new Thread(() -> {
            try {
                thread2.join();// thread2 -> thread3
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("线程3执行了");
        });
        // 下面的start方法可以按任意顺序写
        thread3.start();
        thread2.start();
        thread1.start();

        thread3.join();
        System.out.println("主线程执行了");
    }
}

2.3执行结果

 

测试用例共三个线程,设定执行顺序为 thread1 -> thread2 -> thread3

3.wait、notify概念及使用

3.1概念

使用 notify 和 wait 需要获取对象锁才可以,需要配合 synchronized 使用。
* wait 会释放对象锁,sleep不会释放
* notify 唤醒竞争该对象锁的进程(唤醒1个)
* notifyAll 唤醒竞争该对象锁的所有进程

3.2Demo

public class WaitNotifyDemo {
    public static void main(String[] args) throws InterruptedException {
        // 使用Obeject 即可作为对象锁
        Object o = new Object();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " 开始执行");
                synchronized (o){
                    try {
                        o.wait();// 释放锁
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                System.out.println(Thread.currentThread().getName() + " 执行完成");
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);// 确保thread1先执行
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(Thread.currentThread().getName() + " 开始执行");
                System.out.println(Thread.currentThread().getName() + " 执行完成");
                synchronized (o){
                    o.notify();
                }
            }
        });

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println("主线程 执行");
    }
}

3.3执行结果

Thread-0先启动,然后启动Thread-1;Thread-0调用wait方法被阻塞,Thread-1调用notify唤醒Thread-0。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值