• 【java学习—十五】线程的通信(6)



    1. 线程通信

    wait()notify()notifyAll()

        ①wait():令当前线程挂起并放弃 CPU 、同步资源,使别的线程可访问并修改共享资源,而当前线程排队等候再次对资源的访问
        ②notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待
        ③notifyAll():唤醒正在排队等待资源的所有线程结束等待 .

        注意:Java.lang.Object 提供的这三个方法只有在 synchronized 方法synchronized 代码块中才能使用,否则会报 java.lang.IllegalMonitorStateException 异常(这三种方法只能在有同步锁的方法或者代码块中)

    1.1. wait() 方法:

    在当前线程中调用方法: 对象名.wait()

        功能:使当前线程进入等待(某对象)状态 ,直到另一线程对该对象发出 notify ( 或 notifyAll) 为止。

        调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)

        调用此方法后,当前线程将释放对象监控权 ,然后进入等待
        在当前线程被 notify 后,要重新获得监控权,然后从断点处继续代码的执行。

    1.2. notify()/notifyAll() 方法

    在当前线程中调用方法: 对象名.notify()

        功能:唤醒等待该对象监控权的一个线程。

        调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)


    举例:

    package day15;
    
    public class Test2 {
    	public static void main(String[] args) {
    		
    		//定义账户对象
    		Account a = new Account();
    		
    		//多线程对象
    		User u_weixin = new User(a, 2000);
    		User u_zhifubao = new User(a, 2000);
    		
    		Thread weixin = new Thread(u_weixin, "微信");
    		Thread zhifubao = new Thread(u_zhifubao, "支付宝");
    		
    		weixin.start();
    		zhifubao.start();
    	}
    }
    
    class Account{
    	public static int money = 3000;//全局变量,所有操作共享这个变量
    	
    	/**
    	 * synchronized修饰代码块,想要根据不同的对象有不同的锁
    	 * synchronized(a)这个小括号中传入不同的对象就是不同的锁
    	 * @param m
    	 */
    	public void drawing5(int m, Account a) {
    		
    		synchronized(a) {//表示通过方法的参数传递进来的对象的代码块被加了synchronized同步锁
    			//不同的对象就有不同的同步锁
    			String name = Thread.currentThread().getName();
    			
    			//如果是微信操作,先不执行,等待支付宝操作,支付宝操作完,微信再继续操作
    			if(name.equals("微信")) {
    				try {
    					a.wait();//当前的线程进入等待的阻塞状态
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    			}
    			
    			if(money < m) {
    				System.out.println(name + "操作,账户金额不足:" + money);
    			}else {
    				System.out.println(name + "操作,账户原有金额:" + money);
    				System.out.println(name + "操作,取款金额:" + m);
    				
    				money = money - m;
    				
    				System.out.println(name + "操作,取款后的余额:" + money);
    			}
    			
    			if(name.equals("支付宝")) {
    				try {
    					a.notify();//唤醒当前优先级最高的线程,进入就绪状态
    					//a.notifyAll();//唤醒当前所有的线程,进入就绪状态(效果和notifyAll()一样)
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
    				
    			}
    		}
    	}
    	
    	
    	
    }
    
    class User implements Runnable{
    	
    	Account account;
    	int money;
    	
    	public User(Account account, int money) {
    		this.account = account;
    		this.money = money;
    	}
    	
    	@Override
    	public void run() {
    		
    		account.drawing5(money, account);		
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    运行结果:(先执行支付宝的线程,再执行微信的线程)

    在这里插入图片描述

  • 相关阅读:
    golang之slice并发访问
    JavaScript:实现AvlTree树算法(附完整源码)
    二分图及其衍生
    嵌入式Linux驱动开发(I2C专题)(一)
    学编程始于C语言,但只学C远远不够的!
    Docker容器编排技术解析与实践
    Java InputStream.read()如何读取数据流字节并存储到缓冲区数组呢?
    STM32 基础学习——GPIO位结构(江科大老师教程)
    自动驾驶中的决策规划
    React 知识点:基础语法、组件、React-Router、Redux
  • 原文地址:https://blog.csdn.net/weixin_44883789/article/details/134446946