生产者——消费者——队列——锁

消费者和生产者模式

一.概念
1.生产者消费者不是设计模式,属于线程之间的经典问题,生产者生产什么消费者消费什么,生产者不生产消费者不能消费
实现代码:
先创建一个产品类

package com.qfedu.test1;
/**
 * 	产品类
 * @author WHD
 *
 */
public class Computer {
	private String mainFrame;
	private String screen;
	
	private boolean proState;// 默认值为false表示 可以生产不能消费  值为true表示可以 消费 不能生产
	
	public boolean isProState() {
		return proState;
	}
	public void setProState(boolean proState) {
		this.proState = proState;
	}
	public String getMainFrame() {
		return mainFrame;
	}
	public void setMainFrame(String mainFrame) {
		this.mainFrame = mainFrame;
	}
	public String getScreen() {
		return screen;
	}
	public void setScreen(String screen) {
		this.screen = screen;
	}
	public Computer() {
	}
	public Computer(String mainFrame, String screen) {
		this.mainFrame = mainFrame;
		this.screen = screen;
	}
	@Override
	public String toString() {
		return "Computer [mainFrame=" + mainFrame + ", screen=" + screen + "]";
	}
	
	
	
}

再创建生产者类,代码如下:

package com.qfedu.test1;
/**
 * 	生产者
 * @author WHD
 *
 */
public class Productor extends Thread{
	private Computer com;
	
	public Productor(Computer com) {
		this.com = com;
	}



	@Override
	public void run() {
		// run方法用于生产电脑 
		// 根据for循环i的取值分别生产两种电脑 一共20台
		// i为偶数生产 联想电脑
		// 为奇数生产 华硕电脑
		for (int i = 1; i <= 20; i++) {
			synchronized (com) {
				if(com.isProState()) {
					try {
						com.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				
				if (i % 2 == 0) {
					com.setMainFrame("联想主机" + i);
//					try {
//						Thread.sleep(200);
//					} catch (InterruptedException e) {
//						// TODO Auto-generated catch block
//						e.printStackTrace();
//					}
					com.setScreen("联想显示器" + i);
				} else {
					com.setMainFrame("=======华硕主机=======" + i);
//					try {
//						Thread.sleep(200);
//					} catch (InterruptedException e) {
//						// TODO Auto-generated catch block
//						e.printStackTrace();
//					}
					com.setScreen("=======华硕显示器=======" + i);
				}
				
				com.setProState(true);
				com.notify();
				
			}
		}
	}
}

代码解释:
先定义一个产品,然后写上有参构造,再来个for循环,我们需要生产多少次就让i<=多少,然后用synchronized去锁定我们要传入的产品,使其只能每次只能生产一次,然后判断我们定义的ProState是否为flase,是的话表示现在有产品,需要等待消费者购买以后在进行生产,否则没有产品我们将进行生产,并在生产完成以后把状态修改为true,并随机调用一个其他等待的方法,因本案例中只有一个消费者,故调用消费者
消费者代码:

package com.qfedu.test1;


/**
 * 	消费者
 * @author WHD
 *
 */
public class Consumer extends Thread{
	private Computer com ;
	
	public Consumer(Computer com) {
		this.com = com;
	}

	@Override
	public void run() {
		for (int i = 1; i <= 20; i++) {
			synchronized (com) {
				if(!com.isProState()) {
					try {
						com.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
//				try {
//					Thread.sleep(200);
//				} catch (InterruptedException e) {
//					e.printStackTrace();
//				}
				System.out.println("消费者获取电脑:" + com.getMainFrame() + ">>>>>" + com.getScreen());
				
				
				com.setProState(false);
				com.notify();
			}
		}
	}
}

代码解释:
也是先创建产品类,然后for循环进行购买,判断其状态是否为true,为true则可进行购买,否则则等待生产者生产完,并在购买玩将其状态修改为folase,并调用其它等待的方法。

队列

一.概念:队列可用于解决消费者和生产者一次只能生产一个的情况,队列可自定义生产数量,不必等消费者购买以后进行生产,队列如果满了就不再进行生产,如果队列中没有东西,消费者无法购买,也是多个线程同用一个队列
生产代码:
package com.qfedu.test2;

import java.util.concurrent.ArrayBlockingQueue;

/**
 * 	之前我们使用Object提供一些方法可以实现生产者消费者模式
 * 	但是这种方式有很明显的缺点:
 * 	生产者和消费者严重"捆绑"在一起
 * 	生产者生产一个 消费者才能消费一个 
 * 	我们现实生活 中肯定不是这样的
 * 	所以我们可以使用队列来解决这个问题
 * 	队列 所有的队列都要这样一个特点 FIFO (first in first out )
 * 	Java中的队列由JDK给我们提供的一个接口  Queue<T>
 * 
 * 
 * 	1.先定义生产者和消费者 还是两个线程  
 * 	2.两个线程要使用同一个队列  同一个队列对象
 * 	ArrayBlockingQueue 是基于数组的 通过查看源代码 当前类对象会根据我们传入的长度作为队列的大小 数组的长度
 * @author WHD
 *
 */
public class Test {
	public static void main(String[] args) {
		// 1.队列如果满了就不再往队列中存放
		// 2.消费者如果发现队列中没有内容 不会消费
		
		ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(10);
		Productor pro = new Productor(queue);
//		Consumer con = new Consumer(queue);
		
		pro.start();
//		con.start();
		
		
	}
}

代码解释:
先定义一个队列类,并定义其一次可以生产的数量,然后定义有参构造,重写run方法,for循环我们需要生产的次数,然后用队列对象调用put方法进行生产,不用等待和重新调用,生产满了以后将自动进行等待
消费者代码:

package com.qfedu.test2;

import java.util.concurrent.ArrayBlockingQueue;

/**
 * 	消费者
 * @author WHD
 *
 */
public class Consumer extends Thread{
	private ArrayBlockingQueue<String> queue;
	
	public Consumer(ArrayBlockingQueue<String> queue) {
		this.queue = queue;
	}



	@Override
	public void run() {
		for (int i = 1; i <= 20; i++) {
			try {
				System.out.println("消费者获取到的数据:" + queue.take());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

代码解释:
先定义队列对象,然后for循环,直接在for里进行输出我们获取到的生产者生产的产品,用队列对象.take获取

一.种类:自旋锁(无锁) CAS 轻量级锁(偏向锁) 重量级锁(排它锁) 读写锁 读锁,写锁
可重入锁:同一个线程重复获取一个锁对象 是指synchorized代码块小括号中再有synchorized

package com.qfedu.test3;
/**
 * 	锁 synchronized 
 * 	自旋锁(无锁) CAS 轻量级锁 (偏向锁)  重量级锁(排它锁)   读写锁  读锁 写锁
 * 	锁的粒度 粗  细
 * 	比如有一段代码 程序 在这段代码中有对数据读写的操作  
 * 	我们发现 读数据的操作我们通常不需要上锁 
 * 	写数据的操作都要上锁
 * 	Lock
 * 	可重入锁:同一个线程重复获取同一个锁对象 是指的 synchronized代码块小括号中的内容  不应该产生   死锁
 * 	synchronized属于可重入锁  
 * @author WHD
 *
 */
public class Test1{
//	public void m1() {
//		synchronized (this) {
//			count --;
//		}
//	}
	
	public static void main(String[] args) {
		Object o = new Object();
		synchronized (o) {
			System.out.println("外层同步代码快");
			synchronized (o) {
				System.out.println("内层同步代码块");
			}
		}
		
	}
	

}

自定义可重入锁

package com.qfedu.test3;

/**
 * 	不可重入锁  
 * 	可重入锁:同一个线程重复获取同一个锁对象 (是指的 synchronized代码块小括号中的内容 ) 不应该产生   死锁
 * @author WHD
 *
 */
public class TestLock {
	public MyLock lock = new MyLock();
	
	public static void main(String[] args) throws InterruptedException {
		TestLock test = new TestLock();
		test.m1();
//		test.m2();
		
	}
	
	
	public void m1() throws InterruptedException {
		lock.lock();
		System.out.println("m1方法执行");
		m2();
		lock.unlock();
	}
	
	
	public void m2() throws InterruptedException {
		lock.lock();
		System.out.println("m2方法执行");
		lock.unlock();
	}
	
	
	
}



class MyLock{
	
	// 锁 具备两个功能 一个上锁 一个解锁
	// 我们如何判断当前是该上锁 还是该 解锁 
	private boolean lockState; // 默认值为false 没有上锁  上锁以后改为true
	private Thread thread; // 用于和调用上锁和解锁方法的线程比较 是否为 同一个线程  同一个线程如果重复调用上锁的方法 就不上锁
	private int holdCount; // 上锁的次数 每次上锁就+1 每次解锁就 -1 当值为0的时候 释放锁
	
	public synchronized void lock() throws InterruptedException {
		Thread t = Thread.currentThread();
		while(lockState && t != thread) {
			wait();
		}
		lockState = true;
		thread = t;
		holdCount ++;
	}
	
	
	public synchronized void unlock() {
		Thread t = Thread.currentThread();
		if(t == thread) {
			holdCount --;
			if(holdCount == 0) {
				lockState = false;
				notify();
			}
		}
	}
	
}


代码解释:
先定义一个锁类,定义三个私有参数,一个判断是否上锁,一个判断是否是同一个对象,一个判断上锁次数,定义一个synchronized修饰的上锁方法,然后判断获取当前线程信息赋值给t,然后判断当前是否上锁并且是否是同一线程,当没有上锁,且为同一线程则进行上锁,并修改lockState状态,类记上锁次数。
定义synchronized修饰的开锁方法,然后获取当前线程信息,如果线程为同一线程,则上锁次数减一,然后上锁次数不为0则继续等待下一次开锁操作,将上锁次数继续减一直到为0进行开锁操作,并调用等待的线程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值