生产消费模型

问题:
 &emsp’两个消费者同时访问一个仓库对象,仓库内只有一个元素的时候,两个消费者并发访问,会有可能产生抢夺资源的问题。
解决:
  仓库对象被线程访问的时候,仓库对象被锁定。仓库对象只能被一个线程访问,其他的线程处于等待状态。
利用特征修饰符synchronized,同步,一个时间点只有一个线程访问
线程安全锁两种形式:
  1.将synchronized放在方法的结构上 public synchronized void get(){} 锁定的是调用方法时的那个对象
  2.将synchronized关键字,放在方法(构造方法,块)的内部

public void get(){
	代码
	代码
	synchronized(对象){
		代码
	}
	代码
}
/*
	为什么要这么做呢,因为线程锁定的时候,其他线程必须等到这个线程走完才能走。而当我方法里的代码有非常多,
	但会由于并发产生问题的代码只有几行的时候,就必须用这种方法。不然效率就太低了。
	好比说去上课这个方法,有走楼梯的代码,走楼梯可以一次性很多人走,但是规定进教室一次只能进一个人。
	这样就能发现, 不能因为每次进教室只能进一人而使每次走楼梯也只能走一人。
*/

线程的不同状态来回切换:
执行–等待–执行–等待
wait() 对象.wait();不是当前的这个对象wait,是访问当前这个对象的线程wait();
只等待,不唤醒,会产生一个类似假死的状态,当所有线程进入等待状态,那就没有线程做事情了
notify() notifyAll()唤醒线程

利用线程安全锁,特征修饰符synchronized
两种不同的写法,一定要记住,不管怎么写,锁定的永远是对象
利用方法控制线程状态的来回切换,wait()可以传毫秒值,如果有传,就是等待多久后进入就绪状态,如果没有传,就得等到被唤醒了,才会进入就绪状态
notify() notifyAll()唤醒线程的两个方法
Thread类中的方法:
sleep()静态方法,long类型的毫秒值作为参数
setPriority(1-10);设置线程的优先级
getPriority();获取线程的优先级
优先级越高,越容易获取到CPU分配的时间碎片

sleep和wait
所在类不同,调用方式不同
sleep哪个位置调用,哪个线程等待
wait对象调用这个方法,访问这个对象的其他线程等待
sleep不需要唤醒,wait需要唤醒
sleep不会释放锁,wait等待后会释放锁

生产消费者模型:

主方法:

package com.csdn.study;

public class Test {
    public static void main(String[] args){
        Producer producer = new Producer();  // 生产者
        Consumer consumer1 = new Consumer(); // 消费者
        Consumer consumer2 = new Consumer(); // 消费者

        producer.start();
        consumer1.start();
        consumer2.start();
    }
}

仓库类:

package com.csdn.study;

import java.util.ArrayList;
public class WareHouse {
    // 单例模式,只有一个仓库
    private WareHouse(){}
    private static WareHouse wareHouse = new WareHouse();
    public static WareHouse getInstance(){
        return wareHouse;
    }
    // 仓库里面的集合,存放货物
    private ArrayList<String> list = new ArrayList<>();

    // 添加元素方法
    public synchronized void add(){
        if(list.size() < 20){ // 货物不足20个,继续生产
            System.out.println("生产者生产第" + (list.size() + 1) + "个货物");
            list.add("货物" + (list.size() + 1));
        }else{ // 如果已经有20个货物了。停止生产,叫消费者来拿货物
            try{
                this.notifyAll(); // 先叫醒别人,自己再去睡觉
                this.wait();  // 仓库调用wait方法,不是仓库对象等待,
                            // 是访问仓库的生产者线程等待。
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
    // 从仓库里拿的方法
    public synchronized void get(){
        if(list.size() > 0){  // 还有货物可以拿
            System.out.println("消费者拿走" + list.remove(0));// 每次拿走一个
        }else{ // 没有货物可以拿了
            try {
                this.notifyAll();  // 唤醒生产者
                this.wait(); // 消费者等待
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

生产者类:

package com.csdn.study;

public class Producer extends Thread{
    public Producer(){}
    private WareHouse wareHouse = WareHouse.getInstance();
    public void run(){
        while(true) {  // 不停的生产
            wareHouse.add();
            try {
                Thread.sleep(200);  // 每生产一个货物,就睡200毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

消费者类:

package com.csdn.study;

public class Consumer extends Thread{
    public Consumer(){}
    private WareHouse wareHouse = WareHouse.getInstance();
    public void run(){
        while(true){  // 不停的拿
            wareHouse.get();
            try{
                Thread.sleep(300); // 每拿走一个货物就睡眠300毫秒
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

运行结果:

在这里插入图片描述
如果不加特征修饰符synchronized锁定线程,则会发生异常
为什么会发生异常:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值