我们先从一个生产者一个消费者到多个生产者多个消费者.
先是一个生产者一个消费者的情况:
/*
* 生产者消费者:类似于输入输出机制(单生产者单消费者)
*
* 分析:生产者有生产任务
* 消费者有消费任务
* 这里是多线程
*
* 创建的类:
* 1、生产任务类:描述生产
* 消费任务类: 描述消费
* 生产消费都使用的时产品
* 还要创建产品类;
*
*/
class Product {
private String name; // 产品名称
private boolean flag = false; // 标识
private int count = 1; // 数量
public synchronized void produce(String name) {
if (flag) {//当标记为true,代表已经生产过一次,就让生产线程等待
try {
this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
this.name = name + "--" + count++;
System.out.println(Thread.currentThread().getName() + "---生产--" + this.name);
flag = true; //生产一次,就标记改为true
this.notify(); //唤醒消费线程
}
public synchronized void consume() {
if (!flag) { //当标记为false时,表示已经消费一次,就让消费线程等待
try {
this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "---消费-------" + this.name);
flag = false; //消费一次,就将标记改为false
this.notify(); //唤醒生产线程
}
}
// 生产者
class Producer implements Runnable {
private Product pro;
public Producer(Product pro) {
this.pro = pro;
}
@Override
public void run() {
while (true) {
pro.produce("+商品+");
}
}
}
// 消费者
class Consumer implements Runnable {
private Product pro;
public Consumer(Product pro) {
this.pro = pro;
}
@Override
public void run() {
while (true) {
pro.consume();
}
}
}
public class ProducerConsumerDemo {
public static void main(String[] args) {
Product pt = new Product();
Producer pro = new Producer(pt);
Consumer con = new Consumer(pt);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
t1.start();
t2.start();
}
}
上面代码就是一个生产者一个消费者的情况,显然输出是没有什么问题的.但是,但你改为多个生产者多个消费者就会出现问题.出现的问题就是会出现生产一次生产,两次消费或者生产两次,消费一次的情况.
分析原因:线程被唤醒之后,没有重新判断标记,直接执行了下面的代码
解决:将if换成while
修改后,线程出现了死锁
原因:唤醒的是本方线程,最后导致所有的线程都处于等待状态,notify:是唤醒同锁的任意一个线程
解决:在唤醒的时候,使用notifyAll将所有的线程都唤醒,这样可以保证对方的线程唤醒
package com.qianfeng.test;
/*
* 多生产者,多消费者
* 单生产者单消费者进行了同步之后就没有了安全问题
*
* 那多生产者多消费者?
*
* 例子:
* 两个生产的线程
* 两个消费的线程
*
* 一个生产的任务
* 一个消费的任务
*
* 一个产品
*
* 当有两个生产线程,两个消费线程,会出现生产一次生产,两次消费或者生产两次,消费一次的情况
* 分析原因:线程被唤醒之后,没有重新判断标记,直接执行了下面的代码
* 解决:将if换成while
*
* 修改后,线程出现了死锁
* 原因:唤醒的是本方线程,最后导致所有的线程都处于等待状态,notify:是唤醒同锁的任意一个线程
* 解决:在唤醒的时候,使用notifyAll将所有的线程都唤醒,这样可以保证对方的线程唤醒
*
* 死锁:
* 1、所有的线程都处于等待状态
* 2、同步锁互相嵌套
*
*
*/
class Product1 {
private String name; // 产品名称
private boolean flag = false; // 标识
private int count = 1; // 数量
public synchronized void produce(String name) {
while (flag) {
try {
this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
this.name = name + "--" + count++;
System.out.println(Thread.currentThread().getName() + "---生产--" + this.name);
flag = true;
this.notifyAll();
}
public synchronized void consume() {
while (!flag) {
try {
this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "---消费-------" + this.name);
flag = false;
this.notifyAll();
}
}
// 生产者
class Producer1 implements Runnable {
private Product1 pro;
public Producer1(Product1 pro) {
this.pro = pro;
}
@Override
public void run() {
while (true) {
pro.produce("+商品+");
}
}
}
// 消费者
class Consumer1 implements Runnable {
private Product1 pro;
public Consumer1(Product1 pro) {
this.pro = pro;
}
@Override
public void run() {
while (true) {
pro.consume();
}
}
}
public class ProducerConsumerDemo1 {
public static void main(String[] args) {
Product1 pt = new Product1();
Producer1 pro = new Producer1(pt);
Consumer1 con = new Consumer1(pt);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
JDK1.5之前使用:原来的进行同步的方法 隐式同步
synchronized(对象){把对象称为锁 获取锁 称为锁旗舰或监视器
同步代码
}//释放锁
JDK1.5之后出现的 新的同步方法 显示同步将锁面向对象啦,使用Lock接口创建锁对象
工作原理:
1、创建锁对象,通过创建的Lock接口的子类实现
2、调用lock()方法获取锁
同步的代码
3、调用unlock()方法,释放锁
下面就只看下该的类吧,生产者和消费者以及主函数都是不用改的.
class Product2 {
private String name; // 产品名称
private boolean flag = false; // 标识
private int count = 1; // 数量
//创建锁
private final Lock lock = new ReentrantLock();
//创建一个Condition对象,实现等待,唤醒功能
//分别给生产和消费的线程指定Condition对像
//得到和锁绑定的Condition,控制生产任务的等待,唤醒
private final Condition condition_pro = lock.newCondition();
//得到和锁绑定的Condition,控制消费任务的等待,唤醒
private final Condition condition_con = lock.newCondition();
//生产
public void produce(String name) {
lock.lock();
try {
while (flag) {
try {
condition_pro.await();
} catch (Exception e) {
e.printStackTrace();
}
}
this.name = name + "--" + count++;
System.out.println(Thread.currentThread().getName() + "---生产--" + this.name);
flag = true;
condition_con.signal();
} finally {
lock.unlock();
}
}