Java线程同步

Java线程同步

使用synchronized来同步方法

一个模拟银行账户取款增款的例子

该例子共有4个类,分别是Account(账户类),Bank(取款),Company(增款),Client(用户)。Bank类会模拟100次取款,每次1000,Company类会模拟100次增款,每次1000。用户初始账户为1000,所以正确情况应该是余额依然为1000。

下面是Account源代码:


package com.zk;

public class Account {

    /** 余额 **/
    private double balance;

    /** 查询余额 **/
    public double getBalance(){
        return balance;
    }

    /** 设置余额 **/
    public void setBalance(double balance){
        this.balance = balance;
    }

    /** 增加余额 **/
    public synchronized void addAmount(double amount){
        double tmp = balance;
        try{
            Thread.sleep(10);
        }catch(InterruptedException e){
            e.printStackTrace();
        }

        tmp += amount;
        balance = tmp;
    }

    /** 减少余额**/
    public synchronized void substractAmount(double amount){
        double tmp = amount;
        try{
            Thread.sleep(10);
        }catch(InterruptedException e){
            e.printStackTrace();
        }

        tmp -= amount;
        balance = tmp;
    }
}

Bank代码:


package com.zk;

/** 从银行中取款 **/
public class Bank implements Runnable {

    private Account account;

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

    @Override
    public void run() {
        for(int i=0; i<100; ++i){
            account.substractAmount(1000);
        }
    }

}

Company代码:


package com.zk;

/** 公司会发工资 **/
public class Company implements Runnable {

    private Account account;

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

    @Override
    public void run() {
        for(int i=0; i<100; ++i){
            account.addAmount(1000);
        }
    }

}

Client代码:


package com.zk;

public class Client {

    public static void main(String[] args) {
        //初始账户:1000元
        Account account = new Account();
        account.setBalance(1000);

        Company company = new Company(account);
        Thread companyThread = new Thread(company);

        Bank bank = new Bank(account);
        Thread bankThread = new Thread(bank);

        System.out.printf("Account: Initial Balance: %f.\n",
                account.getBalance());

        //启动两个线程:模拟100次存款(每次1000),100次取款(每次1000)
        companyThread.start();
        bankThread.start();

        try {
            //使用join方法来等待两个线程结束(die)
            companyThread.join();
            bankThread.join();
            System.out.printf("Account: Final Balance: %f.\n.",
                    account.getBalance());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

多次运行结果如下:

运行结果

通过Thread.sleep(10)我们来模拟取款增款时的一个延时。

在去掉addAmount()substractAmount()前面的关键字synchronized以后,当我们再次执行,会发现出现了错误的结果,而且每次结果不一样。这是因为JVM是不保证线程执行顺序,所以每次运行结果不一样。

而当我们添加上synchronized关键字的时候,这个时候当线程A正在执行Account类中标有synchronized方法的时候,如果有其他线程想同时执行synchronized方法,那么它将会阻塞直至线程A所正在执行的synchronized方法结束。同一时刻,只能有一个线程执行一个类中的一个synchronized方法。

在实际使用中,可以使用synchronized来锁一部分代码,而不是整个方法:

synchronized(this){
    //...
}

而且这样还可以根据需要来锁定不同的对象,而不是整个类:

private final Object cinemaA = new Object();
private final Object cinemaB = new Object();

/** 影院A销售票,锁定cinemaA对象即可 **/
public void cinemaASellTickets(){
    synchronized(cinemaA) {
        //...
    }
}

/** 影院B销售票,锁定cinemaB对象即可 **/
public void clinemaBSellTickets(){
    synchronized(cinemaB){
        //...
    }
}

在synchronized代码块中使用条件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值