java--解决多线程问题

我们先从一个生产者一个消费者到多个生产者多个消费者.

先是一个生产者一个消费者的情况:

/*
 * 生产者消费者:类似于输入输出机制(单生产者单消费者)
 * 
 * 分析:生产者有生产任务
 * 消费者有消费任务
 * 这里是多线程
 * 
 * 创建的类:
 * 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();
		}
		
	}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值