文章目录
- 1. 线程通信
- 1.1. wait() 方法:
- 1.2. notify()/notifyAll() 方法
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);
}
}
运行结果:(先执行支付宝的线程,再执行微信的线程)