java(十六):concurrent(1)—生产者与消费者

从并发的最基本的问题说起——生产者与消费者。
在此之前,我们介绍下Object中的两类方法:wait(),notify()

等待与唤醒

包括wait(), wait(long timeout), notify(), notifyAll()。
和Thread中的静态方法sleep(),join(),yield()不同,wait()和notify()是Object中的非静态方法(join也是非静态方法)。

wait()

wait():非静态方法,调用该方法表示当前线程放弃对于当前对象的锁的持有,且当前线程一直停下等待。对象调用该方法需要当前线程持有该对象的锁
看下面一段代码:

Object o = new Object();

System.out.println("start");
try {
    o.wait();
} catch (InterruptedException e) {
    e.printStackTrace();
}
System.out.println("wait");

上述代码运行会报错:
Exception in thread "main" java.lang.IllegalMonitorStateException,因为当前线程(即主线程)没有持有Object对象的锁,而根据Object源码的解释,如果在当前线程调用对象的wait()方法,而当前线程又不持有该对象的锁,那么会出现:IllegalMonitorStateException。
所以正确的用法是:

Object o = new Object();

System.out.println("start");
synchronized (o){
    try {
        o.wait();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
System.out.println("wait");

synchronized方法体获取了o的锁,进而才执行方法体的内容,不会报错。
如果当前线程中调用了wait()方法,即使其他线程释放了该对象的锁,当前线程也无法获取, 必须要被唤醒才行。

notify()

同样是Object的方法,非静态方法,o.notify()用于唤醒一个调用过o.wait()的线程,同样需要在synchronized方法体中执行,即需要当前线程持有o的锁。

另外说一下notifyAll(),肯定就是唤醒所有了。
还有wait(long timeout),表示当前线程除了放弃锁,但只等待timeout的时间,时间一道,就自己唤醒,等待获取锁,相当于等待后在调用o.notifySelf()(这个方法是我自己编的)。

生产者与消费者

我们使用wait(),notify()实现生产者消费者实例如下:

public class Test01{
    private PriorityQueue<Integer> queue=new PriorityQueue<Integer>(5);

    public static void main(String[] args) {
        Test01 object=new Test01();
        Producer producer=object.new Producer();
        Consumer consumer=object.new Consumer();
        producer.start();
        consumer.start();
    }

    class Consumer extends Thread {
        @Override
        public void run() {consume();}
        private void consume() {
            while(true) {
                synchronized (queue) {
                    while(queue.size()==0) {
                        try {
                            System.out.println("队列为空");
                            queue.wait();
                        } catch (Exception e) {
                            e.printStackTrace();
                            queue.notify();
                        }
                    }
                    queue.poll();
                    queue.notify();
                    System.out.println("取走一个元素,还有:"+queue.size());
                }
            }
        }
    }

    class Producer extends Thread {
        @Override
        public void run() {produce();}
        private void produce() {
            while(true) {
                synchronized (queue) {
                    while(queue.size()==5) {
                        try {
                            System.out.println("队列已经满了");
                            queue.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    queue.offer(1);
                    queue.notify();
                    System.out.println("插入一个元素,长度为"+queue.size());
                }
            }
        }
    }
}

输出结果如下(该输出结果一般是固定的):
插入一个元素,长度为1
插入一个元素,长度为2
插入一个元素,长度为3
插入一个元素,长度为4
插入一个元素,长度为5
队列已经满了
取走一个元素,还有:4
取走一个元素,还有:3
取走一个元素,还有:2
取走一个元素,还有:1
取走一个元素,还有:0
队列为空
插入一个元素,长度为1
插入一个元素,长度为2
插入一个元素,长度为3
插入一个元素,长度为4
插入一个元素,长度为5
队列已经满了
取走一个元素,还有:4
取走一个元素,还有:3
取走一个元素,还有:2
取走一个元素,还有:1
取走一个元素,还有:0
队列为空
……
另一种写法不使用notify(),而使用wait(time)如下:

public class Test01{
    private PriorityQueue<Integer> queue=new PriorityQueue<Integer>(5);

    public static void main(String[] args) {
        Test01 object=new Test01();
        Producer producer=object.new Producer();
        Consumer consumer=object.new Consumer();
        producer.start();
        consumer.start();
    }

    class Consumer extends Thread {
        @Override
        public void run() {consume();}
        private void consume() {
            while(true) {
                synchronized (queue) {
                    while(queue.size()==0) {
                        try {
                            System.out.println("队列为空");
                            queue.wait(3000);
                        } catch (Exception e) {
                            e.printStackTrace();
                            queue.notify();
                        }
                    }
                    queue.poll();
                    System.out.println("取走一个元素,还有:"+queue.size());
                }
            }
        }
    }

    class Producer extends Thread {
        @Override
        public void run() {produce();}
        private void produce() {
            while(true) {
                synchronized (queue) {
                    while(queue.size()==5) {
                        try {
                            System.out.println("队列已经满了");
                            queue.wait(3000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    queue.offer(1);
                    System.out.println("插入一个元素,长度为"+queue.size());
                }
            }
        }
    }
}

亲仔细查看代码,生产者消费者应该不难理解。
作为一个引子,本节提出了不使用concurrent包而实现同步的方法,即使用synchronized来实现同步,其实我们一般也是这么做的。在后面我们将分析concurrent里的锁等类,并使用锁实现生产者消费者。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值