[24]多线程生产与消费

版权声明:嘤嘤嘤,小白的东西,大牛们应该看不上吧。 https://blog.csdn.net/qq_37384180/article/details/83718562

 一、用Synchronized代码块

可以根据注释阅读代码

run()方法解析

package synchronized_compro;
/**
 * 资源类(因为资源共享,所以要是单例)
 * 属性:商品名称,商品编号,标识,单例引用
 * */
public class Resource {
	private static final Resource r=new Resource(); //单例
	private String name; //商品名称
	private int num=1; //商品编号
	private boolean flag=false; //标识,用于标识是该生产还是消费
	
	public void setFlag(boolean flag) {
		this.flag = flag;
	}
	public boolean getFlag() {
		return flag;
	}
	
	public void setName(String name) {
		this.name = name+num;
		num++;
	}
	public String getName() {
		return name;
	}
	public static Resource getInstance() {
		return r;
	}
}

package synchronized_compro;

/**
 * 生产类(生产一般是多个,所以用线程)
   属性:资源的对象引用 
   行为:生产
 */
public class Producer implements Runnable {
	private Resource r = Resource.getInstance(); // 单例

	/* 生产 */
	public void set(String name) {
		r.setName("商品");
		System.out.println(Thread.currentThread().getName() + " : 生产 " + r.getName());
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
			while (true) {
				synchronized (r) {
				while (r.getFlag()) {
					try {
						r.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				set("商品");
				r.setFlag(true);
				r.notifyAll();
			}
		}
	}
}
package synchronized_compro;

/**
 * 消费类(消费一般是多个,所以用线程)
 * 属性:资源的对象引用
 * 行为:消费
 * */

public class Consumer implements Runnable{
	private Resource r=Resource.getInstance();//单例
	
	/*消费*/
	public void out() {
		System.out.println(Thread.currentThread().getName()+" : 消费 "+r.getName());
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
			while (true) {
				synchronized (r) {
				while (!r.getFlag()) {
					try {
						r.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				out();
				r.setFlag(false);
				r.notifyAll();
			}
		}
	}
}
package synchronized_compro;

/**
 * 测试类
 * */
public class Demo {
	public static void main(String[] args) {
		Producer p=new Producer(); //实例化生产
		Consumer c=new Consumer(); //实例化消费
		
		Thread t1=new Thread(p);
		Thread t2=new Thread(p);
		
		Thread t3=new Thread(c);
		Thread t4=new Thread(c);
		
		t1.start();
		t2.start();
		
		t3.start();
		t4.start();
	}
}

notifyAll()会造成浪费太多资源,降低性能。notify()会产生死锁。虽说可以使用两个synchronized嵌套代码块,但是这样也会造成死锁

二、利用Lock替代synchronized,利用Condition来替代监视器方法

这样就可以解决只有一个锁难以解决占用资源的缺点

package compro;

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

/**
 * 资源类(因为资源共享,所以要是单例)
 * 属性:商品名称,商品编号
 * */
public class Resource {
	private static final Resource r=new Resource(); //资源
	private String name; //商品名称
	private int num=1; //商品编号
	private boolean flag=false; //标识,用于标识是该生产还是消费
	private static Lock lock=new ReentrantLock(); //锁实例
	private static Condition con1=lock.newCondition(); //生产监视器
	private static Condition con2=lock.newCondition(); //消费监视器
	
	public void setFlag(boolean flag) {
		this.flag = flag;
	}
	public boolean getFlag() {
		return flag;
	}
	
	public void setName(String name) {
		this.name = name+num;
		num++;
	}
	
	public String getName() {
		return name;
	}
    /*对外开放能获取资源对象的方法*/
	public static Resource getInstance() {
		return r;
	}
	/*对外开放能获取Lock对象的方法*/
	public static Lock getLock() {
		return lock;
	}
	/*对外开放能获取Con1对象的方法*/
	public static Condition getCon1() {
		return con1;
	}
	/*对外开放能获取Con2对象的方法*/
	public static Condition getCon2() {
		return con2;
	}
}

package compro;

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

/**
 * 生产类(生产一般是多个,所以用线程
   属性:资源的对象引用 
   行为:生产
 */
public class Producer implements Runnable {
	private Resource r = Resource.getInstance(); //资源
	private Lock lock = Resource.getLock(); //锁
	private Condition con1 = Resource.getCon1(); //监视器

	/* 生产 */
	public void set(String name) {
		r.setName("商品");
		System.out.println(Thread.currentThread().getName() + " : 生产 " + r.getName());
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		lock.lock();
		try {
			while (true) {
				while (r.getFlag()) {
					try {
						con1.await();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				set("商品");
				r.setFlag(true);
				con1.signal();
			}
		} finally {
			// TODO: handle finally clause
			lock.unlock();
		}
	}
}

package compro;

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

/**
 * 消费类(消费一般是多个,所以用线程)
 * 属性:资源的对象引用
 * 行为:消费
 * */

public class Consumer implements Runnable{
	private Resource r=Resource.getInstance(); //资源
	private Lock lock=Resource.getLock(); //锁
	private Condition con2=Resource.getCon2(); //监视器
	
	/*消费*/
	public void out() {
		System.out.println(Thread.currentThread().getName()+" : 消费 "+r.getName());
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		lock.lock();
		try {
			while(true) {
				while(!r.getFlag()) {
					try {
						con2.await();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				out();
				r.setFlag(false);
				con2.signal();
			}
		} finally {
			// TODO: handle finally clause
			lock.unlock();
		}
	}
}

package compro;

/**
 * 测试类
 * */
public class Demo {
	public static void main(String[] args) {
		Producer p=new Producer(); //实例化生产
		Consumer c=new Consumer(); //实例化消费
		
		Thread t1=new Thread(p);
		Thread t2=new Thread(p);
		
		Thread t3=new Thread(c);
		Thread t4=new Thread(c);
		
		t1.start();
		t2.start();
		
		t3.start();
		t4.start();
	}
}

Synchronized代码块的锁,是对象的锁。每个对象都会有一个隐式的锁。会自动的开启和关闭。

而Lock,需要显式的进行开启和关闭是,并且关闭是必须的,不然不关闭的话,就会占用资源。所以利用try/finally的组合,无论怎么样都要关闭。

Condition的作用是则是监视器,利用await()和signal()代替了Object中的wait()和notify()。

猜你喜欢

转载自blog.csdn.net/qq_37384180/article/details/83718562