复习一道面试题:为什么notify()和wait()方法在Object中?
答:因为notify()和wait()需要在同步代码块中使用,并由锁对象调用,而同步锁可以是任意对象,所以任意对象都应该可以调用上述的两个方法。Object是所有对象的父类,所以object的方法才能被所有对象使用。
wait():阻塞当前线程,释放锁资源,停止同步代码块中的执行。
notify():唤醒被wait()阻塞的线程,不释放锁资源,继续执行同步代码块中代码。
生产者和消费者模式是一种经典的多线程关系模式。生产者生产商品,消费者消费商品,商品就是它们的共享资源,因为商品是一个单个物品,所以我们引入一个仓库的概念,用来存放商品。
对于生产者端:仓库中的商品并不会一直增加,它会有一个最大容量。当商品的生产等于最大容量的时候,我们就应该停止商品的生产,通过wait() 阻断生产者这条线程。
对于消费者端:当仓库中有商品时我们就能消费,当仓库中的商品为0,那么消费者端的线程也就应该被阻断。
从上面两段中,我们明白了线程应该什么时间被阻断,那么线程在什么时间应该被唤醒呢?如果仓库中的商品没有满时,就可以唤醒生产者继续生产(消费端一旦消费就说明,仓库就有多余空间,这个时间点就可以使用notify() )。
如果仓库中不为空时,就可以唤醒消费者继续消费,也就是生产者一旦生产一个商品就可以 使用notify(),唤醒消费者去消费商品。
生产者和消费者的共享资源是仓库,它们共享仓库的状态。所以在对仓库的状态进行修改时,必须要先拿到仓库这把锁,才能对仓库进行操作。所以synchronized的锁对象就是它们共用的仓库对象。
下面是生产者和消费者执行关系的Java代码:
类:Comsumer(消费者),Producer(生产者),Repository(仓库),
TestClass(用于代码的测试)
public class Repository {
private int capacity=10; // 仓库容量
private int size=0; // 当前产品数量
public int getCapacity() {
return capacity;
}
public void setCapacity(int capacity) {
this.capacity = capacity;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
}
public class Producer implements Runnable{
private Repository repository;
public Producer() {
}
public Producer(Repository repository) {
this.repository = repository;
}
@Override
public void run() {
while (true) {
if (repository.getSize() >= repository.getCapacity()) {
try {
repository.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
synchronized (repository) {
repository.setSize(repository.getSize() + 1);
System.out.println("生产一个产品-------->当前产品:" + repository.getSize());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
repository.notify();
}
}
}
}
}
public class Consumer implements Runnable{
private Repository repository;
public Consumer() {
}
public Consumer(Repository repository) {
this.repository = repository;
}
@Override
public void run() {
synchronized (repository) {
while (true) {
if (repository.getSize() <= 0) {
try {
repository.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
synchronized (repository) {
repository.setSize(repository.getSize() - 1);
System.out.println("消费一个产品-------->当前产品:" + repository.getSize());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
repository.notify();
}
}
}
}
}
}
public class TestClass {
public static void main(String[] args) {
Repository repository=new Repository();
Consumer consumer=new Consumer(repository);
Producer producer=new Producer(repository);
Thread thread1=new Thread(consumer);
Thread thread2=new Thread(producer);
thread2.start();
thread1.start();
}
}
测试结果:
这里我设置的仓库总容量为:10 ,根据两个线程的执行结果可以看出,两个线程是在相互争抢锁资源,而到达边界资源0的时候,消费者就会阻塞,消费者执行。当生产者生产商品后,两者继续争抢锁资源。

文章讨论了Java中为什么notify()和wait()方法定义在Object类中,因为它们用于多线程同步,可以在任何对象上调用。生产者消费者模式作为示例,解释了何时使用wait()阻塞线程,何时使用notify()唤醒线程。在仓库对象上使用同步机制,确保了生产者和消费者对仓库状态的正确操作。
1588

被折叠的 条评论
为什么被折叠?



