Java线程同步,
分享于 点击 26837 次 点评:77
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代码块中使用条件
相关文章
- 暂无相关文章
用户点评