线程案例及虚假唤醒机制

线程案例

1、创建店员,可以进货,卖货

class Clerk{

    private int product=10;//店里只能放10个货

    //进货
    public synchronized void get(){
        if(product>=10){ //如果店里的货物大于等于10,提醒货满了
            System.out.println("货满了");
        }else{
            System.out.println("进货>"+ ++product); //货不满,进货
        }
    }

    //卖货
    public synchronized void sale(){
        if(product<=0){ //如果货小鱼等于0,表示缺货,无法销售
            System.out.println("缺货");
        }else{
            System.out.println("进货>"+ --product); //有货,可销售
        }
    }
}

2、创建生产者,消费者


//供货商供货
class Supplier implements Runnable{

    private Clerk clerk;
    public Supplier(Clerk clerk) {  //供货商找到店员,你从我这进货
        this.clerk=clerk;
    }

    @Override
    public void run() {
        for(int i=0;i<20;i++){
            clerk.get();
        }
    }
}

//消费者
class Consumer implements Runnable{

    private Clerk clerk;
    public Consumer(Clerk clerk) {  //消费者找到店员,我从你这买
        this.clerk=clerk;
    }

    @Override
    public void run() {
        for(int i=0;i<20;i++){
            clerk.sale();
        }
    }
}

3、运行

  public static void main(String[] args){
        Clerk clerk=new Clerk();
        new Thread(new Supplier(clerk),"生产者").start();
        new Thread(new Consumer(clerk),"消费者").start();
    }

在这里插入图片描述
分析:
1、供货商发现商品满了,会一直提醒店员货满了
2、消费者发现没货了,会一直提醒店员缺货

解决:如果满了,等待,缺货,等待,不满通知
修改代码如下

class Clerk{

    private int product=10;//店里只能放10个货

    //进货
    public synchronized void get(){
        if(product>=10){ //如果店里的货物大于等于10,提醒货满了
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("货满了");
        }else{
            this.notifyAll();
            System.out.println("进货>"+ ++product); //货不满,进货
        }
    }

    //卖货
    public synchronized void sale(){
        if(product<=0){ //如果货小鱼等于0,表示缺货,无法销售
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("缺货");
        }else{
            this.notifyAll();
            System.out.println("卖货>"+ --product); //有货,可销售
        }
    }
}

运行结果
在这里插入图片描述
4、此时在消费这延时消费

//消费者
class Consumer implements Runnable{

    private Clerk clerk;
    public Consumer(Clerk clerk) {  //消费者找到店员,我从你这买
        this.clerk=clerk;
    }

    @Override
    public void run() {
        for(int i=0;i<20;i++){
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.sale();
        }
    }
}

切存货最大为1

 //进货
    public synchronized void get(){
        if(product>=1){ //如果店里的货物大于等于10,提醒货满了
        ...
       

此时会出现问题,运行结束,但是程序没有停止
究其原因:是因为
此处代码已是最终正确的代码
问题处理结果:
将else放开

class Clerk{

    private int product=10;//店里只能放10个货

    //进货
    public synchronized void get(){   //剩余2次  发现product=0,执行++product,product=1,唤醒操作,下次再次执行,会执行此处wait(),程序已走完一直在wait();
        if(product>=1){ //如果店里的货物大于等于10,提醒货满了
            try {
                this.wait();  //如果货满了,等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("货满了");
        }

        System.out.println("进货>"+ ++product); //货不满,进货
        this.notifyAll();  //不满的时候通知,进货
    }

    //卖货
    public synchronized void sale(){ //执行完,product=0,执行wait();这时,继续执行get(),发现product=0;
        if(product<=0){ //如果货小鱼等于0,表示缺货,无法销售
            try {
                this.wait();  //缺货,等待,不销售
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("缺货");
        }

        System.out.println("卖货>"+ --product); //有货,可销售
        this.notifyAll(); //有货,通知卖
    }
}

接下来,多个供货商,多个消费者

  public static void main(String[] args){
        Clerk clerk=new Clerk();
        new Thread(new Supplier(clerk),"生产者").start();
        new Thread(new Consumer(clerk),"消费者").start();

        new Thread(new Supplier(clerk),"生产者1").start();
        new Thread(new Consumer(clerk),"消费者1").start();
    }

执行出现问题:
在这里插入图片描述
卖货很多,但是根本没有,虚假
解决:wait()应总是使用在循环中
if编程while

class Clerk{

    private int product=10;//店里只能放10个货

    //进货
    public synchronized void get(){   //剩余2次  发现product=0,执行++product,product=1,唤醒操作,下次再次执行,会执行此处wait(),程序已走完一直在wait();
        while (product>=1){ //如果店里的货物大于等于10,提醒货满了
            try {
                this.wait();  //如果货满了,等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("货满了");
        }

        System.out.println("进货>"+ ++product); //货不满,进货
        this.notifyAll();  //不满的时候通知,进货
    }

    //卖货
    public synchronized void sale(){ //执行完,product=0,执行wait();这时,继续执行get(),发现product=0;
        while(product<=0){ //如果货小鱼等于0,表示缺货,无法销售
            try {
                this.wait();  //缺货,等待,不销售
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("缺货");
        }

        System.out.println("卖货>"+ --product); //有货,可销售
        this.notifyAll(); //有货,通知卖
    }
}

结果:
在这里插入图片描述

另一种解决方式

使用Lock 和 Condition

package test;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test2 {

    public static void main(String[] args){
        Clerk clerk=new Clerk();
        new Thread(new Supplier(clerk),"生产者").start();
        new Thread(new Consumer(clerk),"消费者").start();

        new Thread(new Supplier(clerk),"生产者1").start();
        new Thread(new Consumer(clerk),"消费者1").start();
    }
}

class Clerk{

    private int product=0;//店里只能放10个货
    private Lock lock=new ReentrantLock();
    private Condition condition=lock.newCondition();
    //进货
    public  void get(){
        lock.lock();
        try {
            while (product>=1){ //如果店里的货物大于等于10,提醒货满了
                try {
                    condition.await(); // 对应 this.wait();  //如果货满了,等待
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("货满了");
            }

            System.out.println("进货>"+ ++product); //货不满,进货
            condition.signalAll(); // 对应 this.notifyAll();  //不满的时候通知,进货
        }finally {
            lock.unlock();
        }
    }

    //卖货
    public  void sale(){
        lock.lock();
        try {
            while(product<=0){ //如果货小鱼等于0,表示缺货,无法销售
                try {
                    condition.await(); // 对应 this.wait();  //缺货,等待,不销售
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("缺货");
            }

            System.out.println("卖货>"+ --product); //有货,可销售
            condition.signalAll(); // 对应 this.notifyAll(); //有货,通知卖
        }finally {
            lock.unlock();
        }
    }
}

//供货商供货
class Supplier implements Runnable{

    private Clerk clerk;
    public Supplier(Clerk clerk) {  //供货商找到店员,你从我这进货
        this.clerk=clerk;
    }

    @Override
    public void run() {
        for(int i=0;i<20;i++){
            clerk.get();
        }
    }
}

//消费者
class Consumer implements Runnable{

    private Clerk clerk;
    public Consumer(Clerk clerk) {  //消费者找到店员,我从你这买
        this.clerk=clerk;
    }

    @Override
    public void run() {
        for(int i=0;i<20;i++){
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.sale();
        }
    }
}

实例:三个线程按照顺序循环打印ABCABCABC…

package test;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test3 {
    public static void main(String[] args){
        Print print = new Print();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<=20;i++){
                    print.printA();
                }
            }
        },"A").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<=20;i++){
                    print.printB();
                }
            }
        },"B").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<=20;i++){
                    print.printC();
                    System.out.println("--------------------------------");
                }
            }
        },"C").start();
    }
}

class Print{
    private int currentThreadId=1;
    private Lock lock = new ReentrantLock();
    private Condition condition1=lock.newCondition();
    private Condition condition2=lock.newCondition();
    private Condition condition3=lock.newCondition();

    public void printA(){
        lock.lock();
        try {

            if(currentThreadId !=1){
                condition1.await();
            }

            System.out.println("A");

            currentThreadId=2;
            condition2.signal();
        }catch (Exception e){

        }
        finally {
            lock.unlock();
        }
    }


    public void printB(){
        lock.lock();
        try {
            if(currentThreadId !=2){
                condition2.await();
            }

            System.out.println("B");

            currentThreadId=3;
            condition3.signal();
        }catch (Exception e){

        }
        finally {
            lock.unlock();
        }
    }


    public void printC(){
        lock.lock();
        try {

            if(currentThreadId !=3){
                condition3.await();
            }

            System.out.println("C");

            currentThreadId=1;
            condition1.signal();
        }catch (Exception e){

        }
        finally {
            lock.unlock();
        }
    }
}

结果:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值