Java线程的通信
当需要多个线程共同完成一件任务,而且需要有规律的执行,那么多个线程之间需要一定的通信机制,可以协调他们的工作,以此实现多线程共同操作一份数据。
1 等待唤醒机制
这是一种线程间的协作机制,与争夺锁的竞争机制相对应,当一个线程满足某个条件时,就进入等待状态( wait/wait(m) ),等到其他线程执行完指定的代码后,再将其唤醒,或者可以指定时间,到时间了自动唤醒,有多个线程等待时,如果有需要,可以notifyAll()唤醒所有等待的线程,wait/notify就是一种线程间的协助机制。
wait()
- 作用:使当前线程等待,直到其他线程调用相同对象的
notify()
或notifyAll()
方法,或者线程被中断。 - 使用场景:当一个线程需要等待某个条件发生时,比如资源可用、状态改变等。
- 条件:调用
wait()
方法时,当前线程必须持有该对象的监视器锁(synchronized),否则会抛出IllegalMonitorStateException
异常。
synchronized (sharedObject) {
while (!condition) {
sharedObject.wait(); // 释放锁并等待
}
// 条件满足后的操作
}
notify()
- 作用:唤醒在该对象上等待的一个线程。如果有多个线程在等待,则随机选择一个线程唤醒。
- 使用场景:在某个条件被满足时,通知一个等待的线程继续执行。
synchronized (sharedObject) {
// 修改条件
sharedObject.notify(); // 唤醒一个等待线程
}
notifyAll()
- 作用:唤醒在该对象上等待的所有线程。
- 使用场景:当条件变化可能影响所有等待线程时,使用
notifyAll()
确保所有线程都有机会重新检查条件。
synchronized (sharedObject) {
// 修改条件
sharedObject.notifyAll(); // 唤醒所有等待线程
}
2 例子
2.1 两个线程共同卖票,一人一张
public class Ticket {
public static void main(String[] args) {
TicketTask t1 = new TicketTask();
TicketTask t2 = new TicketTask();
t1.start();
t2.start();
}
static class TicketTask extends Thread {
static int ticket = 200;
static final Object lock = new Object();
@Override
public void run() {
while (true) {
synchronized (lock) {
lock.notifyAll();
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() +" " + ticket);
ticket--;
}
else {
break;
}
try {
lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
}
2.2 两个线程共同交替从1加到100
public class TestAdd {
static int i = 0;
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
while (true) {
synchronized (this){
this.notify();
if (i < 100) {
System.out.println(Thread.currentThread().getName() + "---" + ++i);
}
else {
break;
}
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
};
new Thread(runnable).start();
new Thread(runnable).start();
}
}