Java多线程实例(synchornized)

1.相关知识点

格式:

	synchronized 返回值类型 方法名称(形参列表0) {//对当前对象(this)加锁
		//代码(原子操作)
	}

注意:只有调用同步方法或包含同步代码块的方法时,才需要对象的锁标记,其他的普通方法则不用

2.实例

以“丈夫”、“妻子”两条线程取钱为例【此例中运用到了代理模式】,何时加锁?–>写操作需要,读则不用

/**
 *银行账户类
 */
public class Account {
    //账号、密码、取钱数
    private String cardnum;
    private String password;
    private Double money;

    public Account(String cardnum, String password, Double money) {
        this.cardnum = cardnum;
        this.password = password;
        this.money = money;
    }

    //取款(原子操作,从插卡验证,到取款成功的一系列步骤,不可缺少或打乱)
    public synchronized void getmoney(String cardnum,String password,Double money) throws InterruptedException {
        //模拟读卡
        Thread.sleep(2000);
        System.out.println("欢迎您,"+Thread.currentThread().getName()+",正在读卡中...");
        //验证账户
        if(this.cardnum.equals(cardnum)&&this.password.equals(password)){
            //模拟读卡
            Thread.sleep(1000);
            System.out.println("验证成功!正在读取余额,请稍后...");
            this.readmoney(this.money);
            if(this.money>=money){
                Thread.sleep(1000);
                System.out.println("正在取钱,请留意出钞口!");
                //余额减少
                this.money-=money;
                System.out.println(Thread.currentThread().getName()+"取款成功,账户余额为"+this.money+"元!");
            }else{
                System.out.println(Thread.currentThread().getName()+":抱歉,您的帐户余额不足!");
            }
        }else{
            System.out.println("验证失败,请重新登录!");
        }
    }
//    读取存款,不是原子操作,无需加锁
    public void readmoney(Double money) throws InterruptedException {
        Thread.sleep(1000);
        System.out.println(Thread.currentThread().getName()+":余额为"+money+"元!");
    }
}
//丈夫线程
public class Husband implements Runnable {
    Account account;

    public Husband(Account account) {
        this.account = account;
    }

    @Override
    public void run() {
//        代理模式应用,该线程不知道取钱逻辑,于是委托atm线程去取钱
        try {
            //模拟中进来必须要休眠一秒,否则谁先启动谁就能抢到cpu,看不出两个线程的竞争
            Thread.sleep(1000);
            this.account.getmoney("12345","ac132",1000.00);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
//妻子线程
package com.basic.multithreading.ATM;

/**
 *妻子取钱线程
 */
public class Wife implements Runnable {
    Account account;

    public Wife(Account account) {
        this.account = account;
    }

    @Override
    public void run() {
//        代理模式应用,该线程不知道取钱逻辑,于是委托atm线程去取钱
        try {
            Thread.sleep(1000);
            this.account.getmoney("12345","ac132",1000.00);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
//test
public class ATMTest {
    public static void main(String[] args) {
        //临界资源:同一张银行卡
        //临界资源对象只有一把锁!
        Account account = new Account("12345","ac132",1900.00);
        //Create threads
        Thread husband = new Thread(new Husband(account),"丈夫");
        Thread wife = new Thread(new Wife(account),"妻子");
//        System.out.println(husband); //Thread[丈夫,5,main]
        //Start threads
        husband.start();
        wife.start();
    }
}

3.总结

上述实例中:

  • 取款操作是原子操作,故对此方法做了同步处理(加锁);如果是读取存款,则不需要做同步处理,即不需要用锁标记
  • 代码解析:
    • 新建一个银行账户,这个银行账户作为临界资源,所以对它的写操作(getmoney)需要加锁,而对它的读操作(readmoney)则无需加锁
    • 以唯一的account为参创建“丈夫”和“妻子”两个线程并启动两个线程
    • 线程启动后自动调用run方法准备取钱,但是发现线程中并无取款的相关逻辑,于是委托account对象调用getmoney方法完成取款业务【代理模式】
    • account对象调用getmoney方法,发现这个方法作了同步处理,于是竞争到的线程先进去执行业务,后抢到cpu的线程则等待getmoney“开锁”
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值