Java使用同步代码块

为了解决线程安全问题,Java的多线程支持引入了同步监视器来解决这个问题,使用 同步监视器的通用方法就是同步代码块。

同步代码块的语法格式如下:

synchronized (obj) 

    {

        //同步代码块 }

}

obj叫做同步监视器(即锁对象),任何线程进入下面同步代码块之前必须先获得对obj 的锁;其他线程无法获得锁,也就执行同步代码块。这种做法符合:“加锁­修改­释放锁”的逻辑。锁对象可以是任意对象,但必须保证是同一对象任何时刻只能有一个线程可以获得对同步监视器的锁定,当同步代码块执行完成后该线程会释放对该同步监视器的锁定。

示例代码:

首先使用一个javaBean类模拟用户账户信息

package com.gx.threaddemo;

 

import java.io.Serializable;

 

publicclass Account implements Serializable {

    privatestaticfinallongserialVersionUID = 1L;

    // 银行账户

    private String number;

    // 账户余额

    privatedoublemoney;

    public Account(Stringnumber, double money) {

        this.number = number;

        this.money = money;

    }

    public String getNumber(){

        returnnumber;

    }

    publicvoid setNumber(Stringnumber) {

        this.number = number;

    }

    publicdouble getMoney() {

        returnmoney;

    }

    publicvoid setMoney(double money) {

        this.money = money;

    }

}

创建一个线程类模拟取钱过程

class TakeMoney extends Thread {

    // 谁取钱

    private String name;

    // 账户对象

    private Account account;

    // 取款金额

    privatedoubletakeMoney;

    public TakeMoney(Stringname, Account account, double takeMoney) {

        this.name = name;

        this.account = account;

        this.takeMoney = takeMoney;

    }

    @Override

    publicvoid run() {

        // 加锁

        synchronized (account) {

            if (takeMoney <= account.getMoney()) {

                System.out.println(this.name + "取钱成功,取出" + takeMoney + "元");

                // 线程暂停 10ms 模拟网络传输

                try {

                    sleep(10);

                }catch(InterruptedException e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

                }

                // 修改余额

                double money = account.getMoney() - takeMoney;

                System.out.println("计算余额 = " + money);

                account.setMoney(money);

                System.out.println("账户:" + account.getNumber() + "余额为: "

                        +account.getMoney());

            }else {

                System.out.println(this.name + "取钱失败,原因:" + account.getNumber()

                        +"账户余额不足!");

            }

        }

        //  同步代码块执行结束,线程释放同步锁

    }

}

创建两个线程并运行,模拟AB两人同时取钱情况

package com.gx.threaddemo;

 

import java.util.Random;

publicclass TakeMoneyDemo {

    publicstaticvoid main(String[] args){

        Accountaccount = new Account("666666", 5000);

        //TakeMoney 使用了同步代码块,不存在安全问题

        TakeMoneytakeMoney1 = new TakeMoney("小明", account, 1000);

        TakeMoneytakeMoney2 = new TakeMoney("小红", account, 4500);

 

        // 通过随机数,随机先启动某个程序

        Randomrandom = new Random();

        int randmoInt =random.nextInt(100);

        if (randmoInt % 2 ==0) {

            takeMoney1.start();

            takeMoney2.start();

        }else {

            takeMoney2.start();

            takeMoney1.start();

        }

        // 等待子线程结束

        try {

            Thread.sleep(1000);

        }catch(InterruptedException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

        System.out.println(account.getNumber()+ "账户最终余额:" + account.getMoney());

    }

}

代码执行结果如下,这样就不会出现超取的情况:


  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值