java线程-从生产者和消费者模型说起

Posted on 2009-06-06 09:35 thui 阅读(1348) 评论(0)  编辑  收藏 所属分类: java技术
今天学习了经典的生产者和消费者模型,引起了对java线程等知识的一系列的思考。
在平时的编程中,经常遇到一个线程要产生数据,而另一个线程要处理产生出来的数据,这其实就是生产者和消费者的关系。生产者在产生数据后可以直接调用消费者处理数据;也可以把数据放在一个缓冲区中,让消费者从缓冲区中取出数据处理,两种方式从调用方式上来说,第一种可是说是同步的,即生产者在生产出数据后要等待消费者消耗掉后才能生产下一个数据,等待时间的长短取决于消费者处理数据的能力;第二种方式是异步的,生产者只管生产数据,然后扔到一个缓冲区内,不管数据是否被立即处理了,消费者则从缓冲区中依次取出数据进行自己节奏的处理。从线程模型角度来说,第一种是单线程的,而第二种则是多线程的。多线程必须要考虑的一个问题是线程之间的协作,协作即协调合作,不要乱套,以生产者和消费者模型而言,就是当缓冲区里没有数据时消费者要等待,等待生产者生产数据,当缓冲区满的时候生产者要等待,等待消费者消耗掉一些数据空出位置好存放数据。
java中为了实现多线程之间的协助,需要用到几个特性:wait(),notify(),notifyAll(),synchronized,synchronized相当于操作系统里的临界区或者锁的概念,所谓临界区就是说一次只能有一个线程进去,其他想进入的线程必须等待,加了synchronized锁后,才能调用wait(),notify()和notifyAll()操作,wait方法被调用后,当前线程A(举例)进入被加锁对象的线程休息室,然后释放锁,等待被唤醒。释放的锁谁来获取?当然是由先前等待的另一个线程B得到,B在获得锁后,进行某种操作后通过notify或者notifyAll把A从线程休息室唤醒,然后释放锁,A被唤醒后,重新获取锁定,进行下一语句的执行。
再回到生产者和消费者模型,如果引入了缓冲区的话就需要处理生产者线程和消费者线程之间的协作,缓冲区可以有这几种,队列缓冲区,比如队列或者栈,队列缓冲区的特点是其长度是动态增长的,这就意味着内存的动态分配带来的性能开销,同时队列缓冲区还会产生因为多线程之间的同步和互斥带来的开销。环形缓冲区可以解决内存分配带来开销的问题,因为环形缓冲区长度是固定的。但是环形缓冲区还是无法解决同步互斥带来的多线程切换的开销,如果生产者和消费者都不止一个线程,带来的开销更大,终极解决办法是引入双缓冲区,何为双缓冲区?双缓冲区顾名思义是有两个长度固定的缓冲区A B,生产者和消费者只使用其中一个,当两个缓冲区都操作完成后完成一次切换,开始时生产者开始向A里写数据,消费者从B里读取数据,当A写满同时B也读完后,切换一下,这时消费者从A里取数据,生产者向B写数据,由于生产者和消费者不会同时操作同一个缓冲区,所以不会发生冲突
生产者和消费者模型不止是用在多线程之间,不同进程之间也可以有。线程和进程到底有什么区别?这是很多程序员搞不清的问题,其实很简单,进程有自己的地址空间和上下文,线程是在一个进程上并发执行的代码段。其实在win32系统中进程只是占用一定长度的地址空间,进程中总是有一个主线程来运行。消费者和生产者模型应用于进程间通信的典型例子是分布式消息处理,消息的消费者进程需要一个缓冲区缓冲收到的消息,消息的生产者进程也需要一个缓冲区缓冲将要发送的消息,这样可以一定程度上减少因为网络断开引起的消息丢失。

只有注册用户登录后才能发表评论。


网站导航:
 

posts - 11, comments - 8, trackbacks - 0, articles - 4

Copyright © thui