您的位置:首页 > 编程语言 > Java开发

Java 多线程编程之六:线程之间的通信(附源代码)

2014-06-23 14:06 579 查看
Java 多线程编程之六:线程之间的通信(附源代码)

源代码下载

多线程编程中,线程之间的通信是一个比较复杂的问题。大家往往搞不懂什么是竞争资源?什么时候考虑同步?怎么进行同步?什么是线程通信?怎么进行通信?很多朋友面试的时候都遇到过这样类似的一个编程题:给定一个场景,编写代码来恰当使用等待、通知和通知所有线程。相信很多朋友对java.lang.Object类的这三个方法都很熟悉,notify、notifyAll、wait,但是真正能运用自如的却不多。因此面试中挂在上面那个面试题上的朋友还真不在少数。本文列举了一个经典的生产者、消费者源代码,以代码的角度来说明这个问题,并附加示例源代码,相信读者看过之后对线程之间的通信交互会有更进一步的认识!

生产者-消费者模型,堪称多线程程序中的经典。本源码中将使用 java.lang.Object 的 wait、notify、notifyAll 来实现这个模型,这才是最重要的。

开始以前,让我们先来熟悉一下生产者-消费者模型的游戏规则:

1、仓满不能生产;

2、藏空不能消费;

3、消费者消费产品前发现不能满足此次消费后通知生产者进行生产;

4、生产者生产出产品后通知消费者进行消费。

好的。开始之前再来回顾一下对象锁的概念……这是最关键的。每个对象都有一个内置锁。当程序运行到非静态 synchronized 方法上时,将自动获得与正在执行代码类的当前实例(即 this 实例)有关的锁。java.lang.Thread.sleep() 方法执行时并不释放此锁;java.lang.Object.wait() 方法执行时释放此锁。好了,就到这里吧,说太多了一来显得作者罗嗦,二来也有侮辱读者 Java 基础的嫌疑。开始代码演示。

生产者-消费者模型-仓库源代码

[java] view
plaincopyprint?

package com.defonds.thread;

/**

*

*

* 项目名称:ThreadApp

* 类名称:Godown

* 类描述:生产者-消费者模型之仓库

* 创建人:Defonds

* 创建时间:2010-1-26 上午10:50:00

* 修改人:Defonds

* 修改时间:2010-1-26 上午10:50:00

* 修改备注:

* @version

*

*/

public class Godown {

private final int max_size = 100;//最大库存容量

private int curNum;//现有库存量

/**

*

* 创建一个新的实例 Godown.

*

* @param curNum

*/

public Godown(int curNum){

this.curNum = curNum;

}

/**

* 生产指定数目的产品

*/

public synchronized void produce(int needNum){

while(true){

/**

* 如果不需要生产,进入等待状态

*/

while(this.curNum + needNum > this.max_size){

System.out.println(Thread.currentThread().getName() + "要生产的产品数量" + needNum + "已经超出剩余库存容量" + (this.max_size - this.curNum) +",暂时不能进行生产任务!");

try {

this.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

/**

* 满足了生产条件,进行产品生产

*/

this.curNum += needNum;

System.out.println(Thread.currentThread().getName() + "已经生产了" + needNum + ",现存库存量是为:" + this.curNum);

/**

* 唤醒在此对象监视器上等待的所有线程

*/

this.notifyAll();

}

}

/**

* 消费指定数目的产品

*/

public synchronized void consume(int needNum){

while(true){

/**

* 如果不可以消费,进入等待状态

*/

while(this.curNum < needNum){

System.out.println(Thread.currentThread().getName() + "要消费的产品数量" + needNum + "已经超出剩余库存量" + this.curNum + ",暂时不能进行消费!");

try {

this.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

/**

* 满足了消费条件,进行产品消费

*/

this.curNum -= needNum;

System.out.println(Thread.currentThread().getName() + "已经消费了" + needNum + ",现存库存量是为:" + this.curNum);

/**

* 唤醒在此对象监视器上等待的所有线程

*/

this.notifyAll();

}

}

}

生产者-消费者模型-生产者源代码

[java] view
plaincopyprint?

package com.defonds.thread;

/**

*

*

* 项目名称:ThreadApp

* 类名称:Producer

* 类描述:生产者-消费者模型之生产者

* 创建人:Defonds

* 创建时间:2010-1-26 上午10:45:30

* 修改人:Defonds

* 修改时间:2010-1-26 上午10:45:30

* 修改备注:

* @version

*

*/

public class Producer extends Thread{

private int needNum;//每次要生产产品的数量

private Godown godown;//仓库

/**

*

* 创建一个新的实例 Producer.

*

* @param needNum

* @param godown

*/

public Producer(int needNum,Godown godown){

this.needNum = needNum;

this.godown = godown;

}

/**

* 重写 java.lang.Thread 的 run 方法

*/

public void run(){

this.godown.produce(this.needNum);

}

}

生产者-消费者模型-消费者源代码

[java] view
plaincopyprint?

package com.defonds.thread;

/**

*

*

* 项目名称:ThreadApp

* 类名称:Consumer

* 类描述:生产者-消费者模型之消费者

* 创建人:Defonds

* 创建时间:2010-1-26 上午10:50:48

* 修改人:Defonds

* 修改时间:2010-1-26 上午10:50:48

* 修改备注:

* @version

*

*/

public class Consumer extends Thread{

private int needNum;//每次要消费产品的数量

private Godown godown;//仓库

/**

*

* 创建一个新的实例 Consumer.

*

* @param needNum

* @param godown

*/

public Consumer(int needNum,Godown godown){

this.needNum = needNum;

this.godown = godown;

}

/**

* 重写 java.lang.Thread 的 run 方法

*/

public void run(){

this.godown.consume(this.needNum);

}

}

生产者-消费者模型-程序入口源代码

[java] view
plaincopyprint?

package com.defonds.thread;

/**

*

*

* 项目名称:ThreadApp

* 类名称:ThreadApp

* 类描述:生产者-消费者模型之程序入口

* 创建人:Defonds

* 创建时间:2010-1-26 上午10:51:15

* 修改人:Defonds

* 修改时间:2010-1-26 上午10:51:15

* 修改备注:

* @version

*

*/

public class ThreadApp {

public static void main(String[] args) {

/**

* 仓库初始化

*/

Godown godown = new Godown(30);

/**

* 消费者初始化

*/

Consumer consumer0 = new Consumer(30,godown);

Consumer consumer1 = new Consumer(20,godown);

Consumer consumer2 = new Consumer(40,godown);

/**

* 生产者初始化

*/

Producer producer0 = new Producer(10,godown);

Producer producer1 = new Producer(10,godown);

Producer producer2 = new Producer(10,godown);

Producer producer3 = new Producer(10,godown);

Producer producer4 = new Producer(10,godown);

Producer producer5 = new Producer(10,godown);

Producer producer6 = new Producer(10,godown);

Producer producer7 = new Producer(10,godown);

/**

* 标记每个生产者/消费者

*/

consumer0.setName("consumer0");

consumer1.setName("consumer1");

consumer2.setName("consumer2");

producer0.setName("producer0");

producer1.setName("producer1");

producer2.setName("producer2");

producer3.setName("producer3");

producer4.setName("producer4");

producer5.setName("producer5");

producer6.setName("producer6");

producer7.setName("producer7");

/**

* 开始进行生产-消费

*/

consumer0.start();

consumer1.start();

consumer2.start();

producer0.start();

producer1.start();

producer2.start();

producer3.start();

producer4.start();

producer5.start();

producer6.start();

producer7.start();

}

}

一次执行本代码时的控制台输出片段:

consumer2已经消费了40,现存库存量是为:20

consumer2要消费的产品数量40已经超出剩余库存量20,暂时不能进行消费!

consumer0要消费的产品数量30已经超出剩余库存量20,暂时不能进行消费!

consumer1已经消费了20,现存库存量是为:0

consumer1要消费的产品数量20已经超出剩余库存量0,暂时不能进行消费!

consumer0要消费的产品数量30已经超出剩余库存量0,暂时不能进行消费!

consumer2要消费的产品数量40已经超出剩余库存量0,暂时不能进行消费!

producer5已经生产了10,现存库存量是为:10

producer5已经生产了10,现存库存量是为:20

producer5已经生产了10,现存库存量是为:30

producer5已经生产了10,现存库存量是为:40

producer5已经生产了10,现存库存量是为:50

producer5已经生产了10,现存库存量是为:60

producer5已经生产了10,现存库存量是为:70

producer5已经生产了10,现存库存量是为:80

producer5已经生产了10,现存库存量是为:90

producer5已经生产了10,现存库存量是为:100

producer5要生产的产品数量10已经超出剩余库存容量0,暂时不能进行生产任务!

producer1要生产的产品数量10已经超出剩余库存容量0,暂时不能进行生产任务!

producer0要生产的产品数量10已经超出剩余库存容量0,暂时不能进行生产任务!

producer2要生产的产品数量10已经超出剩余库存容量0,暂时不能进行生产任务!

producer4要生产的产品数量10已经超出剩余库存容量0,暂时不能进行生产任务!

producer3要生产的产品数量10已经超出剩余库存容量0,暂时不能进行生产任务!

producer6要生产的产品数量10已经超出剩余库存容量0,暂时不能进行生产任务!

producer7要生产的产品数量10已经超出剩余库存容量0,暂时不能进行生产任务!

consumer2已经消费了40,现存库存量是为:60

consumer2已经消费了40,现存库存量是为:20

consumer2要消费的产品数量40已经超出剩余库存量20,暂时不能进行消费!

consumer0要消费的产品数量30已经超出剩余库存量20,暂时不能进行消费!

consumer1已经消费了20,现存库存量是为:0

consumer1要消费的产品数量20已经超出剩余库

当然,本程序还存在一点问题,那就是一旦某个生产者得到 CPU 资源后,生产出一次产品后,尽管使用 notifyAll,但是却并没有让出 CPU 资源,以至于其他生产者无法再得到 CPU 资源;消费者也是如此。相信聪明的读者会找到更佳的办法来解决这个问题。但本例子主要是用来给大家演示线程之间的交互,就这一点需求来说,本例子足够了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: