多线程案例
生产者消费者模型与仓储模型的区别
生产者消费者没有仓库,生产者和消费者操作的从始至终就只有一个位置上的东西,生产者放一个,消费者拿一个。"取"和"放"的细节放在了"消费者"和"生产者"线程的实现中。
仓储模型有一个仓库,仓库有容量,生产者和消费者可以操作的数量取决于仓库的容量,生产者和消费者取和放的数量取决于谁抢到了资源。"取"和"放"的细节在仓库类中实现,生产者和消费者线程只负责调用。
应用场景
多个线程去操作同一个资源,并且多个线程的功能都是一样的:
卖票案例
多个线程去操作同一个资源,并且多个线程的功能都不一样的就用:
生产者消费者模型 or 仓储模型
代码实现
多窗口售票案例
一个售票任务:销售1000张票,3个窗口来进行销售。
类型:一个任务,分发给多个线程,每个线程的任务相同
package com.sun.sell_ticket;
public class Test01 {
public static void main(String[] args) {
Task task = new Task();
Thread t1 = new Thread(task,"窗口001");
Thread t2 = new Thread(task,"窗口002");
Thread t3 = new Thread(task,"窗口003");
t1.start();
t2.start();
t3.start();
}
}
//Task
public class Task implements Runnable {
private static int allTicket = 1000;
private static int curTicket = 0;
@Override
public void run() {
while(curTicket < allTicket){
synchronized(this){
String name = Thread.currentThread().getName();
if(curTicket<allTicket){
System.out.println(name + "正在销售第" + (++curTicket) + "张票");
}
if(curTicket >= allTicket){
System.out.println(name+ "票已售完");
}
}
}
}
}
生产者消费者模型
让生产者和消费者线程操作同一个产品类的对象
两产品之间来回切换(目的:分辨模型运行结果是否出错)
加锁,生产者设置完产品属性,消费者才能抢到资源,进行消费
生产一个,消费一个
分析:生产者线程、消费者线程、手机类
//Test01
public class Test01 {
public static void main(String[] args) {
Phone phone = new Phone();
Producer p1 = new Producer(phone);
Producer p2 = new Producer(phone);
Consumer c1 = new Consumer(phone);
Consumer c2 = new Consumer(phone);
p1.start();
p2.start();
c1.start();
c2.start();
}
}
//Consumer
public class Consumer extends Thread {
private Phone phone;
public Consumer(Phone phone,String name){
super(name);
this.phone = phone;
}
@Override
public void run() {
while(true){
synchronized(phone){
String name = Thread.currentThread().getName();
while(!phone.isStore()){
try {
phone.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(name + "购买了" + phone.getBrand()+ " -- " + phone.getPrice());
phone.setStore(false);
phone.notifyAll();
}
}
}
}
//Producer
public class Producer extends Thread {
private static boolean flag = true;
private Phone phone;
public Producer(){
}
public Producer(Phone phone,String name){
super(name);
this.phone = phone;
}
@Override
public void run() {
while(true){
synchronized(phone){
while(phone.isStore()){
try{
phone.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
if(flag){
phone.setBrand("华为");
phone.setPrice(5999);
}else{
phone.setBrand("三星");
phone.setPrice(3999);
}
flag = !flag;
phone.setStore(true);
phone.notifyAll();
}
}
}
}
//Phone
public class Phone {
private String brand;
private double price;
private boolean store;
public Phone(){
}
public Phone(String brand,double price){
this.brand = brand;
this.price = price;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public boolean isStore() {
return store;
}
public void setStore(boolean store) {
this.store = store;
}
}
仓储模型
生产者不断的生产面包,将面包放入仓库
消费者不断消费面包,从仓库中拿出
要做到先生产的面包先卖出
分析:仓库类、生产者线程、消费者线程、面包类
//Test01
package com.qf.store02;
public class Test01 {
public static void main(String[] args) {
Store store = new Store();
Producer p1 = new Producer(store);
Producer p2 = new Producer(store);
Consumer c1 = new Consumer(store);
Consumer c2 = new Consumer(store);
p1.start();
p2.start();
c1.start();
c2.start();
}
}
//Cake
public class Cake {
private String brand;
private String datetime;
public Cake() {
}
public Cake(String brand, String datetime) {
this.brand = brand;
this.datetime = datetime;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getDatetime() {
return datetime;
}
public void setDatetime(String datetime) {
this.datetime = datetime;
}
@Override
public String toString() {
return "Cake [brand=" + brand + ", datetime=" + datetime + "]";
}
}
//Consumer
public class Consumer extends Thread{
private Store store;
public Consumer(Store store) {
this.store = store;
}
@Override
public void run() {
while(true){
store.pop();
}
}
}
package com.qf.store02;
import java.time.LocalDateTime;
import com.qf.store02.Cake;
//生产者线程
public class Producer extends Thread{
private Store store;
public Producer(Store store) {
this.store = store;
}
@Override
public void run() {
while(true){
Cake cake = new Cake("桃李面包", LocalDateTime.now().toString());
store.push(cake);
}
}
}
//Store
package com.qf.store02;
import java.util.LinkedList;
public class Store {
private static final int MAX_CAPACITY = 20;
private LinkedList<Cake> list;
private int curCapacity;
private int maxCapacity;
public Store() {
this(MAX_CAPACITY);
}
public Store(int capacity) {
list = new LinkedList<>();
maxCapacity = capacity;
}
//入库
public synchronized void push(Cake cake){
while(curCapacity >= maxCapacity){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.add(cake);
curCapacity++;
System.out.println("入库 -- 当前库存量为:" + curCapacity);
notifyAll();
}
//出库
public synchronized Cake pop(){
while(curCapacity <= 0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Cake cake = list.removeFirst();
curCapacity--;
System.out.println("出库 -- 当前库存量为:" + curCapacity + " -- " + cake);
notifyAll();
return cake;
}
}