多线程经典消费者实例
来源:互联网 发布:数据库主键约束有哪些 编辑:程序博客网 时间:2024/06/07 17:12
需求
我们的程序想要实现这样的一个功能,两个线程,一个不断往一个容器加数据,一个不断从这个容器取数据。
设计的问题
我们的第一个问题是,如果容器满了怎么办,空了又怎么。解决的办法是使用wait()和notify()。思路是当容器满或空时,对应的线程就应该停下了,等到不空或者不满的时候再继续。显然wait()和notify()可以很好的实现。当空时,暂停取,使用wait(),添加线程添加了后就不空了,就可以使用notify()唤醒取的线程了。满的时候也是一样的。
sleep()和wait()的区别
暂停也可用sleep(),为什么不用sleep()呢?首先是我们不知道停多久,有notify()配合使用才方便。sleep()和wait()有一个重要的区别是,sleep()不会让出对象锁。我们写个例子来证明下:
class Lock{ public synchronized void printlnTest(){ for(int i=0;i<100;i++) System.out.println(Thread.currentThread().getName()); } public synchronized void sleepTest(){ System.out.println("sleeped 2 second"); try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}class Print implements Runnable{ private Lock lock; public Print(Lock lock){ this.lock = lock; } @Override public void run(){ lock.printlnTest(); }}class SleepTest implements Runnable{ private Lock lock; public SleepTest(Lock lock){ this.lock = lock; } @Override public void run(){ lock.sleepTest(); }}public class SleepAndWait { public static void main(String[] args) { Lock lock = new Lock(); Print print = new Print(lock); SleepTest sleep = new SleepTest(lock); new Thread(sleep).start(); new Thread(print).start(); }}
输出的结果是,输出了sleeped 2 second,等待两秒后,才可以看到输出的100个Thread-1。如果把synchronized去掉,也就是不加锁,Thread-1会立即输出不会等两秒。这里证明sleep是不会让出对象锁的。
非常有用的线程图
消费者实例
这是容器,使用一个类似栈的容器
public class Stack { private char[] container = new char[6]; private int top;//指向栈顶元素的上一个 public synchronized void push(char a){ if(top==container.length){//if 改为while更合适,思考下为什么 try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } this.notify(); container[top]=a; top++; System.out.println(Thread.currentThread().getName()+"入栈的元素"+a); } public synchronized char pop(){ if(top==0){//if 改为while更合适,思考下为什么 try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } this.notify(); top--; System.out.println(Thread.currentThread().getName()+"出栈的元素:"+container[top]); return container[top]; }}
生产者
public class Producer implements Runnable{ private Stack stack; public Producer(Stack stack){ this.stack = stack; } @Override public void run(){ for(int i=0;i<10;i++){ stack.push((char)('a'+i)); } }}
消费者
public class Consumer implements Runnable{ private Stack stack; public Consumer(Stack stack){ this.stack = stack; } @Override public void run(){ try { for(int i=0;i<10;i++) stack.pop(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
主线程
public class ThreadTest { public static void main(String[] args) { Stack stack = new Stack(); Producer p = new Producer(stack); Consumer c = new Consumer(stack); Thread t1 = new Thread(p); Thread t2 = new Thread(c); t1.start(); t2.start(); }}
同步的问题
当添加线程的push方法和取线程的pop方法,不是原子操作时意思就是push方法执行一半,cpu切换给pop方法的线程执行,就会出现问题。比如说,当执行了container[top]=a;但是还没执行top++;切换到取线程时,把原来栈顶的元素取出来了并且指针向下减,如果再返回添加线程,继续执行top++;结果就是新添加的元素丢失了,原来栈顶的元素取了一次还在。所以pop方法和push方法要加锁,作为原子操作。
0 0
- 多线程经典消费者实例
- 经典多线程Java实例 生产者与消费者
- 经典多线程实例:生产者消费者问题
- 多线程经典实例;生产者和消费者
- 多线程经典的 生产者-消费者 实例
- 多线程:生产者消费者实例
- 经典的生产者消费者-----多线程
- 黑马程序员——多线程操作经典实例:生产者消费者问题
- 多线程——等待唤醒机制经典实例:生产者消费者模式
- 多线程——等待唤醒机制经典实例:生产者消费者模式(优化)
- 多线程八 生产者消费者经典问题
- java多线程之生产者消费者经典问题
- 多线程经典问题-生产者与消费者
- 多线程之经典生产者消费者问题
- java多线程之生产者消费者经典问题
- 多线程第八篇 生产者消费者经典问题
- 多线程八 生产者消费者经典问题
- java多线程之生产者消费者经典问题
- 浅析栈区和堆区内存分配的区别
- 微信小程序网络请求
- Java之美[从菜鸟到高手演变]之Exception
- SQL中having和where的用法区别
- IO读写(一) java
- 多线程经典消费者实例
- JAVA基础编程50道,值得收藏
- JAVA内存分配(1)---堆和栈
- 新手学习javaScript的第一个实例
- nginx_知识(反向代理)
- 单例模式
- iOS中数组遍历的方法及比较
- PHP 文件
- 基因演算法解决函数极值问题-python版