线程的同步

由于同一个进程的多个线程共享存储空间,在带来方便的同时也产生了一些访问冲突的问题。如果两个线程同时访问一个共享变量(如例子中的余额balance),会造成最终结果不符合实际需求的情况。

Java中引入了“对象互斥锁”的概念(又称为监视器)来实现不同线程对共享数据操作的同步。“对象互斥锁”不允许多个线程对象同时访问同一个条件变量,即同一时刻最多只有一个线程对象访问共享数据。

我们通过private修饰变量,让变量只能被方法访问,所以针对方法提出一套机制——synchronized关键字,它包含两种用法:synchronized修饰方法和synchronized修饰程序快。

一、synchronized修饰方法

  格式:public synchronized void withdrawal(double amount){}

  该机制保证了同一时刻内,一个类实例中所有声明synchronized的方法最多只有一个处于可执行的状态,从而避免了类成员变量的访问冲突。

  所以synchronized只用修饰会访问共享变量的方法即可,而常规方法不用,synchronized修饰方法的案例请看“线程的通信中第一个例子”。

二、synchronzed修饰程序块

  格式:synchronized(syncObject){

     //允许访问控制的代码

     }

  synchronized程序块是对一个类实例对象进行上锁,保证该类实例对象同一时刻只能被一个线程访问。代码如下:

public class BankDriver {
    public static void main(String[] args) {
        //初始化一个银行账号,余额为2000
        Bank bank = new Bank("001", 2000);

        //开启两个Operation线程对象对bank账号进行取款操作
        for (int i=0;i<2;i++){
            new Operation(i+"#",bank, (double) 1200,1).start();
        }
    }
}

public class Operation extends Thread {
    //定义银行账户对象、操作金额变量、存取款flag(1代表取款,0代表存款)
    Bank bank;
    double amount;
    int flag;

    public Operation(String name) {
        super(name);
    }

    public Operation(String name,Bank bank,Double amouot,int flag){
        super(name);
        this.bank = bank;
        this.amount = amouot;
        this.flag = flag;
    }

    @Override
    public void run() {
        //将bank设置为上锁对象,通过flag判断是存款还是取款执行对应逻辑
        synchronized(bank){
            if (flag == 1) {
                if (bank.getBalance() >= amount){
                    System.out.println("****************************");
                    bank.setBalance(bank.getBalance() - amount);
                    System.out.println("已取出" + amount + "元,\n目前余额为:" + bank.getBalance() + "元。");
                    System.out.println("****************************");
                }else {
                    System.out.println("余额不足!");
                }
            } else {
                bank.setBalance(bank.getBalance() + amount);
                System.out.println("*********************************");
                System.out.println("已存入" + amount + "元,\n目前余额为:" + bank.getBalance() + "元。");
                System.out.println("*********************************");
            }
        }
    }
}

public class Bank {
    //账户id和余额
    private String bankID;
    private double balance;

    public Bank() {
    }

    public Bank(String bankID, double balance) {
        this.bankID = bankID;
        this.balance = balance;
    }

    public String getBankID() {
        return bankID;
    }

    public void setBankID(String bankID) {
        this.bankID = bankID;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }
}

  结果如下:如果没有设置线程同步机制,可能会造成余额为负。

 

转载于:https://www.cnblogs.com/HelloBigTable/p/10830866.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值