您的位置:首页 > 编程语言 > Java开发

Java线程同步

2015-06-28 11:04 666 查看

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代码块中使用条件

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: