java实现生产者-消费者模型

1.方式一:使用synchronize以及wait()、notify() /notifyAll() 的配合使用

package producercomsumer;

/**
 * 描述:
 * 
 * @author: fangchangtan
 * @version 创建时间:2019年1月7日 下午7:19:26
 */
public class ChangtanTest {

	public static void main(String[] args) {
		String lock = "lock";
		for (int i = 0; i < 3; i++) {
			Thread thread1 = new Consumer(lock);
			thread1.start();
		}
		for (int i = 0; i < 3; i++) {
			Thread thread2 = new Producer(lock);
			thread2.start();
		}
	}

}

class Consumer extends Thread {

	private String lock;

	public Consumer(String lock) {
		this.lock = lock;
	}

	public void getValue() {
		try {
			synchronized (lock) {
				if (ValueObject.value == null) {
					lock.wait();
				}
				System.out.println("Consumer:" + ValueObject.value);
				ValueObject.value = null;
				lock.notifyAll();
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void run() {
		while (true) {
			getValue();
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

class Producer extends Thread {

	private String lock;

	public Producer(String lock) {
		this.lock = lock;
	}

	public void setValue() {
		try {
			synchronized (lock) {
				if (ValueObject.value != null) {
					lock.wait();
				}
				ValueObject.value = System.currentTimeMillis() + "";
				System.out.println("Producer:" + ValueObject.value);
				lock.notifyAll();
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void run() {
		while (true) {
			setValue();
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

class ValueObject {
	public static String value;
}

方式二、使用lock锁、配合await() 、signal() 方式

package producercomsumer;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 描述:
 * 
 * @author: fangchangtan
 * @version 创建时间:2019年1月7日 下午7:30:26
 */
public class TankTest {

	public static void main(String[] args) {
		ReentrantLock lock = new ReentrantLock();
		Condition condition = lock.newCondition();
		Thread thread1 = new Consumer1(lock, condition);
		Thread thread2 = new Producer1(lock, condition);
		thread1.start();
		thread2.start();
	}

}

class Consumer1 extends Thread {

	private ReentrantLock lock;
	private Condition condition;

	public Consumer1(ReentrantLock lock, Condition condition) {
		this.lock = lock;
		this.condition = condition;
	}

	public void getValue() {
		try {
			lock.lock();
			if (ValueObject.value == null) {
				condition.await();
			}
			System.out.println("Consumer:" + ValueObject.value);
			ValueObject.value = null;
			condition.signal();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	@Override
	public void run() {
		while (true) {
			getValue();
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

class Producer1 extends Thread {

	private ReentrantLock lock;
	private Condition condition;

	public Producer1(ReentrantLock lock, Condition condition) {
		this.lock = lock;
		this.condition = condition;
	}

	public void setValue() {
		try {
			lock.lock();
			if (ValueObject.value != null) {
				condition.await();
			}
			ValueObject.value = System.currentTimeMillis() + "";
			System.out.println("Producer:" + ValueObject.value);
			condition.signal();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	@Override
	public void run() {
		while (true) {
			setValue();
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

方式三:使用java自身提供的同步阻塞队列

略…(晚上有示例,自身参考吧)


自身在使用中遇到的问题:
1.类文件MyMain.java.。主函数实现多线程生产和消费

package producercomsumer;
/** 
* 描述:
* @author: fangchangtan
* @version 创建时间:2019年1月7日 下午6:57:48 
*/
public class MyMain {

	private static String lock = "lock";
//	private static String value = null;
	
	public static void main(String[] args) {
		ProducerX producerX = new ProducerX(lock);
		ComsumerX comsumerX = new ComsumerX(lock);
		producerX.start();
		comsumerX.start();
	}
}
class ValueObject {
	public static String value;
}

生产者ProducerX :

package producercomsumer;

import java.util.Random;

/**
 * 描述:
 * 
 * @author: fangchangtan
 * @version 创建时间:2019年1月7日 下午6:56:16
 */
public class ProducerX extends Thread{

	private String lock;
	private Random random = new Random();
	public ProducerX(String lock) {
		this.lock = lock;
	}

	@Override
	public void run() {
		while (true) {
			try {
				synchronized (lock) {
					if (ValueObject.value != null) {
						lock.wait();
					}
					ValueObject.value = String.valueOf(random.nextInt(100));
					System.out.println("ProducerX: " + ValueObject.value);
					lock.notify();
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}

	}

}

消费者ComsumerX:

package producercomsumer;

import com.sun.org.apache.xalan.internal.lib.ExsltBase;

/**
 * 描述:
 * 
 * @author: fangchangtan
 * @version 创建时间:2019年1月7日 下午6:57:17
 */
public class ComsumerX extends Thread{

	private String lock;
	
	public ComsumerX(String lock) {
		this.lock = lock;
	}

	@Override
	public void run() {
		while (true) {
			try {
				synchronized (lock) {
					if (ValueObject.value == null) {
						lock.wait();
					}
					System.out.println("ComsumerX: " + ValueObject.value);
					ValueObject.value = null;
//					System.out.println("ComsumerX: " + str);
					lock.notify();
				}
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}

	}

}

(以上的代码是没问题的,但是自身在之前的实现过程中出现很多异常情况)
自身在使用存在的问题:
1.自身使用字符串变量String value;来存储生产的消息对象,导致的结果是,生产者生产完之后无法唤醒消费者消费数据。是因为,消费者和生产者操作的不是同一个消息容器或者对象,即:String类型的对象是通过值来传递的,因此做不到多线程共享同一个对象,此处后期改为: ValueObject.value来作为消息缓存的容器,可以正常的生产和消费。

猜你喜欢

转载自blog.csdn.net/fct2001140269/article/details/86094692