Java中多线程间的等待唤醒机制


前言

我们根据之前所学知识,能够使用java中多线程机制模拟出电影院买票流程,但是通过下面的图我们可以看出,三个线程是属于同一类型的线程,它们都是在执行买票这个操作。那么java中又是如何处理不同种类线程间的通信问题的呢?那么就涉及到java多线程间的等待唤醒机制。
在这里插入图片描述

知识点:等待唤醒机制

1. 需求:实现生产线与消费线之间的通信,实现效果是生产者生产一个,消费者消费一个。

  • 生产者角度:有资源尚未被消费,就等待不生产并且通知消费者消费
  • 消费者角度,如果有资源就消费,如果没有资源就等待并通知生产者生产

2. Oject类中

  • void notify ()
    唤醒在此对象监视器上等待的单个线程。
  • void notifyAll ()
    唤醒在此对象监视器上等待的所有线程。
  • void wait ()
    在其他线程调用此对象的 notify () 方法或 notifyAll () 方法前,导致当前线程等待。
  • void wait (long timeout)
    在其他线程调用此对象的 notify () 方法或 notifyAll () 方法,或者超过指定的时间量前,导致当前线程等待。

3. 代码示例

  • 条件:
    1.生产者线程
    2.消费者线程
    3.流通资源
public class 线程间等待唤醒机制 {
    public static void main(String[] args) {
        //创建共享资源
        Student student = new Student();
        //将资源传递给线程,所以线程之间是共享资源的
        SetThread  th1= new SetThread(student);
        GetThread th2 = new GetThread(student);
        th1.start();
        th2.start();

    }

}
//1.生产线程
class SetThread extends Thread{
    private Student student;
    int i=0;
    public SetThread(Student student) {
        this.student = student;
    }

    @Override
    public void run() {
        while (true){
            synchronized (student){
                //能够进入该代码,说明有资源,生产线程就应该等待
                if(student.flag){
                    try {
                        student.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (i % 2 == 0) {
                    student.name = "张三";
                    student.age = 19;
                } else {
                    student.name = "李四";
                    student.age = 23;
                }
                //更改标记
                student.flag=true;
                //通知消费线程去消费
                student.notify();
            }

            i++;
        }



    }
}
//2.消费线程
class GetThread extends Thread{
   private  Student student;
    public GetThread(Student student) {
        this.student=student;
    }

    @Override
    public void run() {
        while (true){
            //既然对象是一个,我们可以将其作为锁对象。这样保持两个同步代码块的锁一致
            synchronized (student){
                //如果没有资源,进入程序等待
                if(!student.flag){
                    try {
                        student.wait();//线程一旦调用等待wait()方法,就会释放锁,即线程没出同步代码块提前释放锁。下次被唤醒 ,从此处唤醒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
                System.out.println(student.name + "," + student.age);
                //消费完资源后,更改标记,通知生产者生产
                student.flag=false;
                student.notify();
            }
        }

    }
}
//资源
class Student{
    public String name;
    public int age;
    //定义一个标记
    public boolean flag=false;//false表示没有资源,true表示有资源
}

执行效果图:
在这里插入图片描述

4.sleep()方法和wait()方法的区别

  • 共同:都可以让线程处于一种阻塞状态
  • wait()方法:导致当前线程处于阻塞状态,直到被另一个线程调用notify ()或notifyAll ()来唤醒,调用该方法,必须要获得锁对象,所以该方法只能在同步方法和同步代码块中用。(notify ()也是需要在同步方法或同步代码块中调用)。wait()方法一旦执行会释放锁,可以使用notify ()直接唤醒。
  • sleep()方法一旦休眠不会释放锁(必须设置时间量),时间不到只能调用Interreput()强行打断。

作业

  • 运用所学知识,编写代码。
    需求:写两个线程,一个线程打印1-52,一个线程打印A-Z,打印结果是12A34B56C78D-----5152Z(即两个数字一个字母)。

  • 代码答案

public class day23作业1 {
    public static void main(String[] args) {
        //创建共享资源
        PrintFunc printFunc = new PrintFunc();
        //将共享资源传入两个子线程中
        DigitalThread th1 = new DigitalThread(printFunc);
        LetterThread th2 = new LetterThread(printFunc);
        th1.start();
        th2.start();

    }
}
//1.数字线程
class DigitalThread extends Thread{
    int i=1;
    private PrintFunc printFunc;

    public DigitalThread(PrintFunc printFunc) {

        this.printFunc = printFunc;
    }

    @Override
    public void run() {
        while (i<=52){
            synchronized (printFunc){
                //进入这段代码,代表打印了数字
                if(printFunc.flag){
                    try {
                        printFunc.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.print(i);
                i++;
                System.out.print(i);
                //打印了数字,更改标志
                printFunc.flag=true;
                //通知字母线程打印
                printFunc.notify();
            }
            i++;
        }
    }
}
//2.字母线程
class LetterThread extends Thread{
    char ch='A';
    private PrintFunc printFunc;

    public LetterThread(PrintFunc printFunc) {
        this.printFunc = printFunc;
    }

    @Override
    public void run() {
        while (ch<=90){
            synchronized (printFunc){
                //进入该代码,表示尚未打印数字
                if(!printFunc.flag){
                    try {
                        printFunc.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //打印了数字,开始打印字母
                System.out.print(ch);
                //更改标志
                printFunc.flag=false;
                printFunc.notify();
            }
            ch++;

        }
    }
}
//3.共享资源
class PrintFunc{
    //定义一个标签
    boolean flag=false;//false代表尚未打印数字
}
  • 结果
    在这里插入图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值