- 必要性:同时运行的线程需要共享数据,要考虑到其它线程的状态和行为,否则不能保证程序运行结果的正确性(一个沙雕问题:银行卡里有100块钱,在ATM取款等待时间,通过手机支付把这100块花出去)
- 同步方法: synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:
① 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
synchronized(syncObject){
//需要同步访问控制的代码
}
②修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
//声明同步方法
访问修饰符 synchronized 返回类型 方法名(){
//方法体
}
③修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
//声明静态方法
访问修饰符 static synchronized 返回类型 方法名(){
//方法体
}
④ 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。
//声明静态方法
访问修饰符 synchronized class 类名{
//属性、方法
}
- 银行取款示例:
/**
* 银行账户类
*/
public class Account {
private int balance=500; //余额
//取款
public void withdraw(int amount){
balance-=amount;
}
public int getBalance() {
return balance;
}
}
/**
* 取款线程类
*/
public class AccountThread implements Runnable {
private Account acct=new Account();//新建银行账户
//取款 synchronized修饰方法进行线程同步
private synchronized void Withdrawal(int amt) throws InterruptedException {
if(acct.getBalance()>=amt){
System.out.println(Thread.currentThread().getName()+"准备取款");
Thread.sleep(500);
acct.withdraw(100);
System.out.println(Thread.currentThread().getName()+"完成取款,账户余额:"+acct.getBalance());
}else{
System.out.println("余额不足,"+Thread.currentThread().getName()+"取款失败,账户余额:"+acct.getBalance());
}
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
Withdrawal(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Test {
public static void main(String[] args) {
AccountThread r=new AccountThread();
Thread one=new Thread(r);
Thread two=new Thread(r);
one.setName("a");
two.setName("b");
//启动线程
one.start();
two.start();
}
}