目录
1、生产者消费者模式
这是多线程同步的经典问题,消费者和生产者同时使用一块缓冲区,消费者需要从缓冲区取东西,同时生产者要生产商品放入缓冲区。缓冲区满时生产者不再生产商品,缓冲区为空时消费者也不能再消费。
生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件。
如下图所示:
分析:
1、设计一个库存类:Store ,push(放入),pop(取出);
2、生产者:调用 push(放入) 多次调用
3、消费者:调用pop(取),多次调用
4、创建多个线程分别模拟生产和消费
库存类:
public class Stock {
private int count=0;//先设置库存为0;
//生产者生产的方法,synchronized锁,让线程同步
public synchronized void push(){
//设仓库的内存为10
if(count<10){
//唤醒所有等待线程
this.notifyAll();
System.out.println(Thread.currentThread().getName()+"生产者在生产,库存:"+count++);
try {
//睡眠100ms,假设生产的时间
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}else {
System.out.println(Thread.currentThread().getName()+"仓库满了,库存:"+count);
try {
//仓库满了,用wait()方法,线程等待释放锁
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public synchronized void pop(){
//库存大于0时消费者才能消费
if(count>0){
//唤醒所有等待线程
this.notifyAll();
System.out.println(Thread.currentThread().getName()+"消费者在消费,库存:"+count--);
try {
//睡眠100ms,假设消费的时间
Thread.sleep(200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}else {
System.out.println(Thread.currentThread().getName()+"库存为0不能消费"+count);
try {
//仓库空了不能消费,用wait()方法,线程等待释放锁
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
生产者类:
public class Producer extends Thread{
private Stock stock;//设置一个Stock类型属性的stock
//构造方法
public Producer(Stock stock) {
this.stock = stock;
}
//重写run()方法
@Override
public void run() {
for (int i = 0; i < 5; i++) {
stock.push();
}
}
}
消费者类:
public class Consumer extends Thread{//继承Thread类
private Stock stock;//设置一个Stock类型属性的stock
//构造方法
public Consumer(Stock stock) {
this.stock = stock;
}
//重写run()方法
@Override
public void run() {
for (int i = 0; i < 5; i++) {
stock.pop();
}
}
}
测试类:
public class test {
public static void main(String[] args) {
//新建一个Stock对象
Stock stock=new Stock();
Producer p1=new Producer(stock);
Producer p2=new Producer(stock);
Consumer c1=new Consumer(stock);
Consumer c2=new Consumer(stock);
p1.start();
p2.start();
c1.start();
c2.start();
}
}
测试结果:
生产消费者用阻塞队列实现:
public class test01 {
public static void main(String[] args) {
BlockingQueue<Integer> queue=new ArrayBlockingQueue<>(10);
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
queue.put(i);//添加元素,容量满后 会阻塞
System.out.println("生产");
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
int value=queue.take();//移除元素,容量为空后,会阻塞
Thread.sleep(200);
System.out.println("消费"+value);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}).start();
}
}
结果:
2、抢红包问题
1、HongBao类
public class HongBao {
private int money;
private int num;
public HongBao(int money, int num) {
this.money = money;
this.num = num;
}
public synchronized int getRedPacket(){
if(num==0){
return 0;
}
if(num==1){
num--;
return money;
}
Random random=new Random();
int amount =random.nextInt(money/num*2-1)+1;
money-=amount;
return num--;
}
}
2、HongBaoThtead类
public class HongBaoTHread implements Runnable{
private HongBao hongBao;
public HongBaoTHread(HongBao hongBao) {
this.hongBao=hongBao;
}
@Override
public void run() {
int amount=hongBao.getRedPacket();
if(amount>0){
System.out.println(Thread.currentThread().getName()+"抢到了"+amount);
}else {
System.out.println(Thread.currentThread().getName()+"没有抢到");
}
}
}
3、测试类:
public class Test01 {
public static void main(String[] args) {
HongBao hongBao=new HongBao(200,10);
for (int i = 1; i < 10; i++) {
new Thread(new HongBaoTHread(hongBao)).start();
}
}
}
结果: