Java中的多线程(生产者和消费者)

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

        复习一道面试题:为什么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的时候,消费者就会阻塞,消费者执行。当生产者生产商品后,两者继续争抢锁资源。

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值