一、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();
}
}
结果: