生产者消费者模型是线程的一个基本问题。这个问题简答点解释就是生产者可以生产消耗品,消费者可以消耗消耗品,生产者生产消耗品的时候,由于消耗品仓库容量是有限的,所以生产到仓库上限数量的时候,会停止生产。而消费者则不断的从仓库拿走消耗品。生产者与消费者的生产与消费两个动作同时进行,就可以使仓库之中的消耗品数量动态的变化。这就是生产者消费者问题啦。这里用到了线程的的概念以及同步的概念。
1.Java中线程的创建方法
(1)通过继承Thread类,构造一个新的线程类,然后在新的类中重写run()方法;
public class producer extends Thread{
public void run() {
do_something...
}
}
(2)通过实现Runable接口,构造一个类,在新的类中重写run()方法,再在创建新的Thread类实例的时候,用特定的构造函数定义。
public class MyThread implements Runnable{
public void run() {
do_something...
}
}
main()函数中:
MyThread t = new MyThread();
Thread tt = new Thread(t);
线程创建好之后通过调用start()方法运行。
2.线程的同步
就生产者消费者这个问题来说,生产者与消费者共同影响的是仓库之中消耗品的数量,生产者增加其数量,消费者减少其数量,我们可以将生产者和消费者看成是两个线程,两个线程之间的同步就意味着其中一个线程改变了仓库之中消耗品的数量,那么,另一个线程之中,也要知道仓库里面消耗品是怎么变化的,这里引入关键字:synchronized
关于这个关键词,列出最近学到的两种用法:
(1)修饰函数;
public synchronized void fun1(){
...
}
这样表示,一个线程(A)在调用这个函数的时候,如果有其他的线程(B)也在调用这一个函数的时候,线程A就只能等待线程B使用完这个函数之后,才能调用这个函数。 (2)修饰代码块。
synchronized(object/variable){
...
}
同样,一个线程(A)在调用这个代码块的时候,如果有其他的线程(B)也在调用这一个代码块的时候,线程A就只能等待线程B使用完这个代码块之后,才能调用这个代码块。括号里面可以是对象,也可以是变量,使用这个代码块的线程,获得其封锁。3.应用到生产者消费者模型
前面的问题描述中说到,生产者与消费者之间的生产与消费者动态的改变着仓库之中消耗品的数量,那么,用编程思想可以这么认为:生产者是一个线程,消费者是一个线程,两者要通过消耗品数量进行同步。
创建同步共享变量:
package code;
public class share {
private int current_num = 0;//当前仓库之中的消耗品数量
private int max_num = 5;//仓库容量上限
private int min_num = 0;//仓库容量下限
public synchronized void produce() {
if (current_num >= max_num) {
System.out.println("product full");
return;
}
current_num++;//生产
System.out.println("produce product" + current_num);
}
public synchronized void comsume() {
if (current_num <= min_num) {
System.out.println("product empty");
return;
}
System.out.println("comsume product" + current_num);
current_num--;//消耗
}
}
创建生产者线程:
package code;
public class producer extends Thread {
share s1;
public producer(share s1) {
this.s1 = s1;
}
public void run() {
for (int i = 0; i < 10; i++) {//生产十次
s1.produce();
try {
Thread.sleep(100);//加这一个进程睡眠是为了看出来生产以后的效果,留足够的时间给消费者消费
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
创建消费者线程:
package code;
public class comsumer extends Thread {
share s1;
comsumer(share s1) {
this.s1 = s1;
}
public void run() {
for (int i = 0; i < 10; i++) {//消耗十次
s1.comsume();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
主函数:
package code;
public class pcStart {
public static void main(String[] args) {
// TODO Auto-generated method stub
share s1 = new share();//定义共享对象
producer p1 = new producer(s1);//定义生产者线程
comsumer c1 = new comsumer(s1);//定义消费者线程
p1.start();
c1.start();
}
}
其中一次的运行结果:
produce product1
comsume product1
produce product1
comsume product1
product empty
produce product1
produce product2
comsume product2
comsume product1
produce product1
produce product2
comsume product2
produce product2
comsume product2
comsume product1
produce product1
produce product2
comsume product2
comsume product1
produce product1
理论上来讲每一次的结果都应该是不相同的,读者们可以通过改变生产者、消费者进程来得出不同的效果。
4.总结
实现生产者消费者模型的方法不止这一种,也有其他的方法,有其他更好的方法的读者,作者也十分愿意想你们学习!
小试牛刀的一篇总结文章,以上文章仅代表个人观点,有什么不足或者是错误欢迎指正和交流