- Object类(并非Thread类)有三个方法:wait(), notify(),notifyAll()可以用于多线程通信
- wait是将当前线程等待,知道其他线程调用该同步监视器的notify方法或者notifyAll方法来唤醒该现线程
- notify是唤醒这个同步监视器上等待的单个线程,但是如果有多个线程再这个同步监视器上等待,那么这个方法唤醒的那个线程将是随机的
- notifyAll唤醒再次同步监视器上等待的所有线程
- 以下示例为一个模拟存钱取钱操作来实现多线程之间的通信
- 通过布尔值flag来决定是存钱操作等待还是取钱操作等待。举例:当flag为假,表示账号里没有钱,这个时候取钱操作将等待(wait()),然后到了存钱操作,因为flag为假,所以可以存钱,再进行完存钱操作之后,将flag置为真,并且唤醒等待的所有线程,这里一个存钱操作就进行完毕了。取钱操作就被唤醒,再次判断flag,flag为真,可以取钱,取钱之后将flag置为假,唤醒其他在等待的所有线程,这是有可能就唤醒了执行到一般正在等待的其他存钱线程
- 以下为代码示例,
import java.util.Objects; public class Account1 { private String accountNo; private double balance; private boolean flag = false; public Account1(){} public Account1(String accountNo, double balance){ this.accountNo = accountNo; this.balance = balance; } public String getAccountNo() { return accountNo; } public void setAccountNo(String accountNo) { this.accountNo = accountNo; } public double getBalance(){ return this.balance; } public synchronized void draw(double drawAccount){ try{ // 如果flag为假,表示账号里没有钱,取钱方法阻塞 if(!flag){ wait(); }else { System.out.println(Thread.currentThread().getName() + " 取钱" + drawAccount) ; balance -= drawAccount; System.out.println("账号余额为" + " " + balance); // 如果flag为真,表示账号里有钱,进行取钱操作,并且将flag置为假之后唤醒其他线程 flag = false; notifyAll(); } }catch (InterruptedException e){ e.printStackTrace(); } } public synchronized void deposit(double depositAccount){ try{ // 如果flag为真,表示账号里有钱,存钱方法阻塞 if(flag){ wait(); }else { System.out.println(Thread.currentThread().getName() + " 存款:" + depositAccount); balance += depositAccount; System.out.println("账户余额为: " + balance); // 如果flag为假,表示账号里没钱,进行存钱操作,并且将flag置为真之后唤醒其他线程 flag = true; notifyAll(); } }catch (InterruptedException e){ e.printStackTrace(); } } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Account1 account1 = (Account1) o; return Double.compare(account1.balance, balance) == 0 && flag == account1.flag && Objects.equals(accountNo, account1.accountNo); } @Override public int hashCode() { return Objects.hash(accountNo, balance, flag); } }
public class DrawThread1 extends Thread{ private Account1 account1; private double drawAmount1; public DrawThread1(String name, Account1 account1, double drawAmount1){ super(name); this.account1 = account1; this.drawAmount1 = drawAmount1; } public void run(){ for(int i=0 ; i<100; i++){ account1.draw(drawAmount1); } } }
public class DespositThread extends Thread{ private Account1 account1; private double depositAmount; public DespositThread(String name, Account1 account1, double depositAmount){ super(name); this.account1 = account1; this.depositAmount = depositAmount; } public void run(){ for(int i=0; i<100; i++){ account1.deposit(depositAmount); } } }
public class DrawTest1 { public static void main(String args[]){ Account1 account1 = new Account1("1234567", 0); new DrawThread1("取钱者", account1, 800).start(); new DespositThread("存款者甲", account1,800).start(); new DespositThread("存款者乙", account1,800).start(); new DespositThread("存款者丙", account1,800).start(); } }
-
上述的是代码代码块的线程通信,实际上还有一张是通过同步锁的实现的线程通信,java提供了一个Condition类来实现线程通信的。Condition示例被绑定在一个同步锁Lock的对象上,它也提供了类似上面说的三种实现线程通信的方法
-
await类似于上面的wait方法。导致当前线程等待
-
signal唤醒在此同步锁对象上等待的一个线程,如果又多个线程在这个同步锁上等待,那么它会随机的唤醒一个线程
-
signalAll唤醒在此同步锁上等待的所有线程
-
-
以下为代码示例,具体的讲解穿插在代码中
import java.util.Objects; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Account1 { private String accountNo; private double balance; private boolean flag = false; // 这两步为实例化一个同步锁对象,并且将一个Condition对象绑定在同步锁对象上 private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); public Account1(){} public Account1(String accountNo, double balance){ this.accountNo = accountNo; this.balance = balance; } public String getAccountNo() { return accountNo; } public void setAccountNo(String accountNo) { this.accountNo = accountNo; } public double getBalance(){ return this.balance; } public void draw(double drawAccount){ lock.lock(); // 同步锁将当前以下内容加锁 try{ // 如果flag为假,表示账号里没有钱,取钱方法阻塞 if(!flag){ condition.await(); // 这里就相当于上面程序的wait(),以下有关condition对象的操作都和上面程序的操作是 // 一一对应的 }else { System.out.println(Thread.currentThread().getName() + " 取钱" + drawAccount) ; balance -= drawAccount; System.out.println("账号余额为" + " " + balance); // 如果flag为真,表示账号里有钱,进行取钱操作,并且将flag置为假之后唤醒其他线程 flag = false; condition. signalAll(); } }catch (InterruptedException e){ e.printStackTrace(); }finally{ lock.unlock(); } } public void deposit(double depositAccount){ lock.lock(); try{ // 如果flag为真,表示账号里有钱,存钱方法阻塞 if(flag){ condition.await(); }else { System.out.println(Thread.currentThread().getName() + " 存款:" + depositAccount); balance += depositAccount; System.out.println("账户余额为: " + balance); // 如果flag为假,表示账号里没钱,进行存钱操作,并且将flag置为真之后唤醒其他线程 flag = true; condition.signalAll(); } }catch (InterruptedException e){ e.printStackTrace(); }finally { lock.unlock(); } } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Account1 account1 = (Account1) o; return Double.compare(account1.balance, balance) == 0 && flag == account1.flag && Objects.equals(accountNo, account1.accountNo); } @Override public int hashCode() { return Objects.hash(accountNo, balance, flag); } }
这是我看李刚编著的《疯狂Java讲义》后总结出来的。
java多线程(10)线程通信
最新推荐文章于 2023-06-14 17:20:14 发布