等待和唤醒的方法
void wait() 导致当前线程等待,知道另一个线程调用该对象的notify()方法或nottifyAll()方法
void notify() 唤醒正在等待对象监视器的单个线程
void notifyAll() 唤醒正在等待对象监视器的所有线程 消费者和生产者 案例
厨师与顾客之间的关系 厨师=》生产者 顾客=》消费者
消费者步骤
1.判断桌子上是否有食物
2.没有就等待
3.有就执行
4.执行完毕之后,桌上的食物就没有了,叫醒生产者生产,食物-1
生产者步骤
1.判断是否有食物,有就不用生产,没有就生产
2.把食物生产出来
3.叫醒消费者
有一个生产者类,有一个消费者类,食物放置的地方,定义一个标记是否存在食物 还有一个测试类
生产者类
public class Cooker extends Thread{
@Override
public void run() {
// 生产者步骤
// 1.判断是否有食物,有就不用生产,没有就生产
// 2.把食物生产出来
// 3.叫醒消费者
while (true){
synchronized (Desk.lock){
if (Desk.count==0){
//只生产10份
break;
}else{
if (!Desk.flag){
//没有食物
System.out.println("我做好饭了");
Desk.flag=true;
Desk.lock.notifyAll();
}else{
//有食物
try {
Desk.lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
消费者类
public class Eat extends Thread{
@Override
public void run() {
// 消费者步骤
// 1.判断桌子上是否有食物
// 2.没有就等待
// 3.有就执行
// 4.执行完毕之后,桌上的食物就没有了,叫醒生产者生产,食物-1
//并不知道自己执行多少次 while循环
while (true){
//需要定义同一把锁,不能定义在消费者类,也不能定义在生产者类,定义在Desk中 共享
synchronized (Desk.lock){
if (Desk.count==0){
break;
}else {
if (Desk.flag){
//有
System.out.println("消费者正在执行");
//修改食物状态
Desk.flag=false;
//唤醒全部生产者
Desk.lock.notifyAll();
Desk.count--;
}else{
//没有就等待,使用什么对象当作锁,那么就必须用这个对象去调用等待和唤醒方法
try {
Desk.lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
静态标记类
public class Desk {
//定义一个标记
//如果为true 表示食物存在,不用创建食物,允许消费者消费
//如果为false,表示食物不存在,需要厨师执行
public static boolean flag=false;
//食物的数量
public static int count=10;
//锁对象,生产者和消费者共享
public static final Object lock=new Object();
}
测试类为
public class Demo {
public static void main(String[] args) {
// 消费者步骤
// 1.判断桌子上是否有食物
// 2.没有就等待
// 3.有就执行
// 4.执行完毕之后,桌上的食物就没有了,叫醒生产者生产,食物-1
// 生产者步骤
// 1.判断是否有食物,有就不用生产,没有就生产
// 2.把食物生产出来
// 3.叫醒消费者
Eat eat=new Eat();
Cooker ck=new Cooker();
eat.start();
ck.start();
}
}
代码这样写 不是很有面向对象特点只是方便理解 需要改写具有面向对象
生产者类:
public class Cooker extends Thread{
private Desk desk;
public Cooker(Desk desk) {
this.desk=desk;
}
@Override
public void run() {
// 生产者步骤
// 1.判断是否有食物,有就不用生产,没有就生产
// 2.把食物生产出来
// 3.叫醒消费者
while (true){
synchronized (desk.getLock()){
if (desk.getCount()==0){
//只生产10份
break;
}else{
if (desk.isFlag()){
//没有食物
System.out.println("我做好饭了");
desk.setFlag(true);
desk.getLock().notifyAll();
}else{
//有食物
try {
desk.getLock().wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
消费者类:
public class Eat extends Thread{
private Desk desk;
public Eat(Desk desk) {
this.desk=desk;
}
@Override
public void run() {
// 消费者步骤
// 1.判断桌子上是否有食物
// 2.没有就等待
// 3.有就执行
// 4.执行完毕之后,桌上的食物就没有了,叫醒生产者生产,食物-1
//并不知道自己执行多少次 while循环
while (true){
//需要定义同一把锁,不能定义在消费者类,也不能定义在生产者类,定义在Desk中 共享
synchronized (desk.getLock()){
if (desk.getCount()==0){
break;
}else {
if (desk.isFlag()){
//有
System.out.println("消费者正在执行");
//修改食物状态
desk.setFlag(false);
//唤醒全部生产者
desk.getLock().notifyAll();
desk.setCount(desk.getCount()-1);
}else{
//没有就等待,使用什么对象当作锁,那么就必须用这个对象去调用等待和唤醒方法
try {
desk.getLock().wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
一些静态标记类
public class Desk {
//定义一个标记
//如果为true 表示食物存在,不用创建食物,允许消费者消费
//如果为false,表示食物不存在,需要厨师执行
//public static boolean flag=false;
private boolean flag;
//食物的数量
//public static int count=10;
private int count;
//锁对象,生产者和消费者共享
// public static final Object lock=new Object();
//使用默认值的时候 可以给初始值 也可以在空参构造给出值 这里我给空参构造值
private final Object lock=new Object();
public Desk() {
this(false,10);
}
public Desk(boolean flag, int count) {
this.flag = flag;
this.count = count;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public Object getLock() {
return lock;
}
@Override
public String toString() {
return "Desk{" +
"flag=" + flag +
", count=" + count +
", lock=" + lock +
'}';
}
}
测试类:
public class Demo {
public static void main(String[] args) {
// 消费者步骤
// 1.判断桌子上是否有食物
// 2.没有就等待
// 3.有就执行
// 4.执行完毕之后,桌上的食物就没有了,叫醒生产者生产,食物-1
// 生产者步骤
// 1.判断是否有食物,有就不用生产,没有就生产
// 2.把食物生产出来
// 3.叫醒消费者
Desk desk=new Desk();
Eat eat=new Eat(desk);
Cooker ck=new Cooker(desk);
eat.start();
ck.start();
}
}
阻塞队列
阻塞队列实现等待唤醒机制
定义一个put方法,定义一个take方法
阻塞队列结构图
BlockingQueue的核心方法:
put(anObject)将参数放入队列,如果放不进去会阻塞
take();取出第一个数据,取不到会阻塞
常见的BlockingQueue:
ArrayBlockingQueue:底层是数组,有界
LinkedBlockingQueue:单层是链表,无界,但不是真正的无界,int的最大值是max
常见实例:
public class Demo {
public static void main(String[] args) throws InterruptedException {
//阻塞队列的基本用法
//创建阻塞队列的对象,容量为1
ArrayBlockingQueue<String> arrayBlockingQueue=new ArrayBlockingQueue<>(1);
//存储元素
arrayBlockingQueue.put("食物");
//取元素 返回值为取出的元素
String take = arrayBlockingQueue.take();
}
}
对消费者和生产者代码的简写
消费者代码:
public class eat extends Thread{
private ArrayBlockingQueue<String> list;
public eat(ArrayBlockingQueue<String> arrayBlockingQueue) {
this.list=arrayBlockingQueue;
}
@Override
public void run() {
while (true) {
try {
String take = list.take();
System.out.println("消费者队列消费了一份食物"+take);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
生产者:
public class cooker extends Thread{
private ArrayBlockingQueue<String> list;
public cooker(ArrayBlockingQueue<String> arrayBlockingQueue) {
this.list=arrayBlockingQueue;
}
@Override
public void run() {
while (true) {
try {
list.put("食物");
System.out.println("厨师在做了一份食物");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
测试类:
public class Demo {
public static void main(String[] args) {
//创建一个阻塞队列 容量为1
ArrayBlockingQueue<String> arrayBlockingQueue=new ArrayBlockingQueue<>(1);
//创建线程并开启
cooker c=new cooker(arrayBlockingQueue);
eat e=new eat(arrayBlockingQueue);
c.start();
e.start();
}
}