线程通信

线程通信中的3个方法:
1.wait():导致当前线程等待,知道其他线程调用该同步监视器的notify()方法或notifyAll()方法来
唤醒该线程。调用wait()方法的当前线程会释放对该同步监视器的锁定。
2.notify():唤醒在此同步监视器上等待的单个线程,如果有多个线程都在此同步监视器上等待,则会选择唤醒
其中一个线程。选择是任意性的,只有当前线程放弃对该同步监视器的锁定之后(使用wait()方法),才可以执行被唤醒的线程。
3.notifyAll():唤醒在此同步监视器上等待的所有线程。只有当前线程放弃对该同步监视器的锁定后,才可以执行被唤醒的线程。

这三个方法属于Object类,必须由同步监视器来调用,可以分为以下两种情况:
1.对于使用synchronized修饰的同步方法,因为该类的默认实例(this)就是同步监视器,所以可以在同步方法中直接调用者3个方法。
2.对于使用synchronized修饰的同步代码块,同步监视器synchronized后括号里的对象,所以必须使用该对象调用这3个方法。

public class Account_1 {
    private String accountNo;
    private double balance;
    private boolean flag = false;

    public Account_1(){}

    public Account_1(String accountNo,double balance){
        this.accountNo = accountNo;
        this.balance = balance;
    }

    public double getBalance(){
        return this.balance;
    }
    public synchronized void draw(double drawAmount){
        try {
            if (!flag) {
                wait();
            }
            else {
                System.out.println(Thread.currentThread().getName()
                        +" 取钱:"+drawAmount);
                balance -= drawAmount;
                System.out.println("账户余额为: "+balance);
                flag = false;
                notifyAll();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void deposit(double depositAmount){
        try {
            if (flag) {
                wait();
            }
            else {
                System.out.println(Thread.currentThread().getName()
                        +" 存款:"+depositAmount);
                balance += depositAmount;
                flag = true;
                notifyAll();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class DrawThread_1 extends Thread{
    private Account_1 account_1;
    private double drawAmount;
    public DrawThread_1(String name,Account_1 account_1,double drawAmount){
        super(name);
        this.account_1 = account_1;
        this.drawAmount = drawAmount;
    }
    //重复100次取款操作
    public void run(){
        for (int i = 0; i < 100; i++) {
            account_1.draw(drawAmount);
        }
    }
}
public class DepositThread extends Thread{
    private Account_1 account_1;
    private double depositAmount;
    public DepositThread(String name,Account_1 account_1,double depositAmount){
        super(name);
        this.account_1 = account_1;
        this.depositAmount = depositAmount;
    }
    //重复100次存款操作
    public void run(){
        for (int i = 0; i < 100; i++) {
            account_1.deposit(depositAmount);
        }
    }
}
public class DrawTest_1 {
    public static void main(String[] args) {
        Account_1 acct1 = new Account_1("1234567",0);
        new DrawThread_1("取钱者", acct1, 800).start();
        new DepositThread("存款者甲", acct1, 800).start();
        new DepositThread("存款者乙", acct1, 800).start();
        new DepositThread("存款者丙", acct1, 800).start();
    }
}

结果显示程序最后被阻塞无法继续向下执行,这是因为3个存款者线程共有300次存款操作,但1个取钱者线程只有100次取钱操作,所以程序最后被阻塞!
阻塞并不是死锁,对于这种情况取钱者线程已经执行结束(因而已经没有线程处于wait()状态了,当然也就不能唤醒了),而存款者线程只是在等待其他线程来取钱而已并不是等待其他线程释放同步监视器!

什么时候释放对同步监视器的锁定呢?

1、当前线程的同步方法、同步代码块执行结束,当前线程释放同步监视器
2、当前线程在同步代码块、同步方法中遇到break、return终止了该代码块、该方法的继续执行。
3、当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致了该代码块、该方法异常结束时。
4、当前线程在同步代码块、同步方法时,程序执行了同步监视器对象的wait()方法,则当前线程暂停,并释放同步监视器

以下情况,线程不会释放同步监视器:
1、当前线程在同步代码块、同步方法时,程序调用了Thread.sleep(),Thread.yield()方法来暂停当期啊线程的执行。
2、当前线程在同步代码块、同步方法时,其他线程调用了该线程的suspend()方法将该线程挂起。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值