线程间的交互:生产者,消费者问题

生产者消费者问题,也称有限缓冲问题,是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
有时,当线程进入synchronized块后,共享数据的状态并不满足它的需要,它要等待其他线程将共享数据改变为它需要的状态后才能执行。但由于此时它占据了该对象的锁,其他线程无法对共享数据进行操作。这时,我们可以用wait()和notify()这两个方法实现线程间的通信。
如果线程调用了某个对象X的wait()方法——X.wait(),则该线程将放入X的wait pool,并且该线程将释放X的锁;当线程调用X的notify()方法——X.notify()时,则将会使对象X的wait pool中的一个线程移入到lock pool,在lock pool中等待X的锁,一旦获得便可执行。notifyAll()可以把对象wait pool中的所有线程都移入lock pool。我们可以使用wait()和notify()实现线程的同步。
当某个线程需要在synchronized块中等待共享数据状态改变时,可以调用wait()方法,这样使该线程等待并且暂时释放共享数据对象的锁,其他线程可以获得该对象的锁并进入synchronized块操作共享数据。当其操作完毕后,调用notify()方法唤醒正在等待的线程重新占有锁并运行。
在系统中,使用某类资源的线程一般称为消费者,产生或释放同类资源的线程称为生产者。生产者-消费者问题是关于线程交互与同步问题的一般模型。

案例演示如下:
利用线程交互, 完成连续打印1-100的数字, 一条线程专门打印奇数,另外一条专门打印偶数。

方法一:

public class Test {
    public static void main(String[] args) {

        //打印奇数的线程
        new Thread(){
            @Override
            public void run() {
                while (true){
                    synchronized (Number.lock){
                        if(Number.number > 100){
                            break;
                        }
                        if(Number.number % 2 != 0){
                            System.out.println("奇数线程打印" + Number.number++);
                            Number.lock.notify();
                        }else {
                            try {
                                Number.lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }.start();

        //打印偶数的线程
        new Thread() {
            @Override
            public void run() {
                while (true){
                    synchronized (Number.lock) {
                        if (Number.number > 100) {
                            break;
                        } else {
                            if (Number.number % 2 == 0) {
                                System.out.println("偶数线程打印" + Number.number++);
                                Number.lock.notify();
                            } else {
                                try {
                                    Number.lock.wait();
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                }
            }
        }.start();
    }
}

class Number{
    //共享数据
    public static int number = 1;

    //锁对象
    public static Object lock = new Object();
}

方法二:

public class Test {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        new Thread(myRunnable, "奇数").start();
        new Thread(myRunnable, "偶数").start();
    }
}

class MyRunnable implements Runnable{

    //共享数据
    private int number = 1;

    @Override
    public void run() {
        while (true){
            synchronized (this){
                if(number > 100){
                    break;
                }
                String name = Thread.currentThread().getName();
                if(("奇数".equals(name) && number % 2 == 0) ||
                 ("偶数".equals(name) && number % 2 != 0)){
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else {
                    System.out.println(name + "线程打印" + number++);
                    this.notify();
                }
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值