前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >4-线程通信,线程状态

4-线程通信,线程状态

作者头像
Ywrby
发布2022-10-27 13:23:02
3010
发布2022-10-27 13:23:02
举报
文章被收录于专栏:Ywrby

线程通信

多个线程因为在同一个进程中,所以互相通信比较容易

线程通信的经典模型:生产者与消费者问题

生产者负责生成商品,消费者负责消费商品,生产不能过剩(仍有数据未被消费时不能生产),消费不能没有(不能消费还没有生产的数据)

模拟案例:

两名消费者拥有一个共享账户,共享资源,三名生产者负责生产资源。

两名消费者去获取资源,资源存在就取出,不存在就等待,唤醒生产者继续生产资源。

生产者生产资源时,发现仍然存在资源就不继续生产,如果没有资源就生产,然后等待,唤醒消费者来消费

注意:

  • 线程通信一定是多个线程操作同一个资源才需要进行通信
  • 线程通信必须先保证线程安全,否则毫无意义,代码也会报错

线程通信的Object提供三种核心方法

  • wait()方法:让当前线程进入等待状态,此方法必须由锁对象调用
  • notify()方法:唤醒当前锁对象上等待状态的某个线程,此方法必须由锁对象调用
  • notifyAll()方法:唤醒当前锁对象上等待状态的全部线程,此方法必须由锁对象调用

代码实现

账户类,定义了存钱和取钱的操作
代码语言:javascript
复制
package ThreadSafety;


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

//定义账户类
public class Account {
    private int cardID;
    private double Money;


    public synchronized void DrawMoney(int m){
        String name =Thread.currentThread().getName();

        try {
            //判断余额是否足够
            if (Money >= m) {
                //开始支付
                System.out.println(name + "用户执行取钱操作,余额充足,支付" + m + "元成功!");
                Money -= m;


            } else {
                //余额不足
                System.out.println(name + "用户执行取钱操作,余额不足,支付失败!");
            }
            System.out.println(name + "用户结束操作,余额" + Money + "元");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //取完钱后,唤醒别人,等待自己
            this.notifyAll();
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    //新定义的存钱类
    public synchronized void SaveMoney(int m){
        String name =Thread.currentThread().getName();

        try {
            //账户没钱的情况下才执行存钱操作
            if (Money == 0) {
                System.out.println(name + "用户执行存钱操作,充入" + m + "元成功!");
                Money += m;
            } else {
                System.out.println(name + "用户执行存钱操作,余额充足,充值失败!");
            }
            System.out.println(name + "用户结束操作,余额" + Money + "元");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //取完钱后,唤醒别人,等待自己
            this.notifyAll();
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    public Account() {
    }

    public Account(int cardID, double money) {
        this.cardID = cardID;
        Money = money;
    }

    public int getCardID() {
        return cardID;
    }

    public void setCardID(int cardID) {
        this.cardID = cardID;
    }

    public double getMoney() {
        return Money;
    }

    public void setMoney(double money) {
        Money = money;
    }
}
线程类:分别规定了存钱线程和取钱线程
代码语言:javascript
复制
package ThreadSafety;


//线程类:将存钱行为看作是一条单独的线程创建
public class SaveThread extends Thread{

    //定义一个成员变量,接收账户对象
    private Account acc;

    public SaveThread(Account acc,String name){
        super(name);
        this.acc=acc;
    }


    @Override
    public void run() {
        //执行存钱操作,每个用户不断尝试存1000元
        while (true) {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            acc.SaveMoney(1000);
        }
    }
}
代码语言:javascript
复制
package ThreadSafety;


//线程类:将取钱行为看作是一条单独的线程创建
public class DrawThread extends Thread{

    //定义一个成员变量,接收账户对象
    private Account acc;

    public DrawThread(Account acc,String name){
        super(name);
        this.acc=acc;
    }


    @Override
    public void run() {
        //执行取钱操作,每个用户不断尝试取1000元
        while (true) {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            acc.DrawMoney(1000);
        }
    }
}
主线程
代码语言:javascript
复制
package ThreadSafety;


//模拟经典案例:生产者与消费者模型
public class Demo2 {
    public static void main(String[] args) {
        //创建共享账户
        Account acc=new Account(111,0);

        //创建两个消费者对象
        Thread consumer1=new DrawThread(acc,"consumer1");
        consumer1.start();
        Thread consumer2=new DrawThread(acc,"consumer2");
        consumer2.start();
        //创建三个生产者
        Thread producer1=new SaveThread(acc,"producer1");
        producer1.start();
        Thread producer2=new SaveThread(acc,"producer2");
        producer2.start();
        Thread producer3=new SaveThread(acc,"producer3");
        producer3.start();


    }
}
运行结果
代码语言:javascript
复制
producer2用户执行存钱操作,充入1000元成功!
producer2用户结束操作,余额1000.0元
consumer2用户执行取钱操作,余额充足,支付1000元成功!
consumer2用户结束操作,余额0.0元
consumer1用户执行取钱操作,余额不足,支付失败!
consumer1用户结束操作,余额0.0元
producer3用户执行存钱操作,充入1000元成功!
producer3用户结束操作,余额1000.0元
producer1用户执行存钱操作,余额充足,充值失败!
producer1用户结束操作,余额1000.0元
consumer2用户执行取钱操作,余额充足,支付1000元成功!
consumer2用户结束操作,余额0.0元
producer2用户执行存钱操作,充入1000元成功!
producer2用户结束操作,余额1000.0元
producer3用户执行存钱操作,余额充足,充值失败!
producer3用户结束操作,余额1000.0元
consumer1用户执行取钱操作,余额充足,支付1000元成功!
consumer1用户结束操作,余额0.0元

······

线程状态

线程状态

导致状态发生条件

NEW(新建)

线程刚刚被创建,但是尚未启动(没有调用start()方法)。只有线程对象,没有线程特征

Runnable(可运行的)

线程可以在Java虚拟机中运行的状态,可能正在运行自己的代码,也可能没有,取决于操作系统处理器。调用了start()方法。

Blocked(锁阻塞)

当一个线程试图获取一个对象锁,而该对象锁被其他的线程锁持有,则该线程进入Blocked状态,当该线程持有锁时,状态将改变为Runnable

Waiting(无限等待)

一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态,进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify()方法或notifyAll()方法才能将线程唤醒

Timed Waiting(计时等待)

同Waiting()状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态,这一状态将一致保持到超时期满或者接收到唤醒通知,带有超时参数的常用方法有:Thread.sleep,Object.wait

Terminated(被终止)

因为run()方法正常退出而死亡,或者因为没有捕获的异常终止了run()方法而死亡

线程状态
线程状态

注意:

可运行状态还可以被细分为两个状态:就绪状态和运行状态,就绪状态只是成功开启线程还没有真正运行,运行状态表示开始正常执行

sleep()和wait()区别在于sleep()休眠后不释放当前锁对象,所以在当前线程苏醒后可以直接继续当前锁对象内容,但是wait()表示释放当前锁对象,所以即便在苏醒后,也需要与其他线程争抢当前锁对象,成功抢到则可以执行,否则又变为锁阻塞状态

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-03-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 线程通信
    • 线程通信的经典模型:生产者与消费者问题
      • 注意:
        • 线程通信的Object提供三种核心方法
          • 代码实现
          • 线程状态
            • 注意:
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档