线程交互
- 线程的交互指线程之间需要一些协调通讯来共同完成任务;
- 线程的交互可以通过 wait() 方法和 notify() 方法来实现;
1. Object() 方法
- 调用 Object 类提供的 wait() 方法时,当前线程停止执行,并释放占有的资源,线程从运行状态转换为等待状态;
- 必须从同步环境内调用 wait() notify() notifyAll() 方法,线程拥有对象的锁才能调用对象等待或通知方法;
- 执行某个对象的 notify() 方法时,会唤醒对象等待池中的某个线程,使该线程从等待状态转换为就绪状态,执行某个对象的 notifyAll() 方法时,会唤醒对象等待池中的所有线程;
- 多个线程在等待一个对象锁时要使用 notifyAll();
类型 | 方法 | 说明 |
---|
void | notify() | 唤醒在此对象监听器上等待的单个线程 |
void | notifyAll() | 唤醒在此对象监听器上等待的所有线程 |
void | wait() | 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,当前线程等待 |
void | wait(long timeout) | 在其他线程调用此对象的 notify() 方法、 notifyAll() 方法、或未超过指定时间前,一个都不满足当前线程等待 |
void | wait(long timeout,int nanos) | 在其他线程调用此对象的 notify() 方法、 notifyAll() 方法前、或未超过指定时间、其他某个线程中断当前线程前,一个都不满足当前线程等待 |
2. 生产者-消费者问题
- 生产者-消费者问题是线程交互的经典问题;
- 生产者将生产的产品放到仓库中,而消费者从仓库取走产品;仓库一次存放固定数量的产品;如果仓库满了,生产者停止生产,等待消费者消费产品;如果仓库不满,生产者继续生产;如果仓库是空的,消费者停止消费,等仓库有产品再继续消费;
public class Test {
public static void main(String[] args) {
Stack s = new Stack();
Producer p = new Producer(s);
Consumer c = new Consumer(s);
new Thread(p).start();
new Thread(p).start();
new Thread(p).start();
new Thread(c).start();
}
}
class Rabbit {
int id;
Rabbit(int id) {
this.id = id;
}
public String toString() {
return "玩具 : " + id;
}
}
class Stack {
int index = 0;
Rabbit[] rabbitArray = new Rabbit[6];
public synchronized void push(Rabbit wt) {
while (index == rabbitArray.length) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notifyAll();
rabbitArray[index] = wt;
index++;
}
public synchronized Rabbit pop() {
while (index == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notifyAll();
index--;
return rabbitArray[index];
}
}
class Producer implements Runnable {
Stack st = null;
Producer(Stack st) {
this.st = st;
}
public void run() {
for (int i = 0; i < 20; i++) {
Rabbit r = new Rabbit(i);
st.push(r);
System.out.println("生产-" + r);
try {
Thread.sleep((int) (Math.random() * 200));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
Stack st = null;
Consumer(Stack st) {
this.st = st;
}
public void run() {
for (int i = 0; i < 20; i++) {
Rabbit r = st.pop();
System.out.println("消费-" + r);
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3. 多线程协作
public class Test {
public static void main(String[] args) {
ThreadB b = new ThreadB();
System.out.print(Thread.currentThread().getName());
b.start();
synchronized (b) {
try {
System.out.println("等待对象b 完成计算……");
b.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("b 对象计算的总和是:" + b.total);
}
}
}
class ThreadB extends Thread {
int total;
public void run() {
synchronized (this) {
for (int i = 0; i < 101; i++) {
total += i;
}
notify();
}
}
}