1.不同步时的代码:
Bank类:
package com;
public class Bank {
private int count=0;
//存钱
public void addMoney(int money) {
count+=money;
System.out.println("成功存进银行"+money+"元");
}
public void subMoney(int money) {
if(count>=money) {
count-=money;
System.out.println("成功取出"+money+"元");
}else {
System.out.println("余额不足");
}
}
public void lookMoney() {
System.out.println("账户余额:"+count);
}
}
测试类:
package com;
public class BankTest {
public static void main(String[] args) {
final Bank bank=new Bank();
Thread tadd=new Thread(new Runnable() {
public void run() {
while(true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
bank.addMoney(100);
bank.lookMoney();
System.out.println("\n");
}
}
});
Thread tsub=new Thread(new Runnable() {
public void run() {
while(true) {
bank.subMoney(100);
bank.lookMoney();
System.out.println("\n");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
tsub.start();
tadd.start();
}
}
运行结果:
余额不足
账户余额:0
成功存进银行100元
账户余额:100
成功取出100元
账户余额:0
余额不足
账户余额:0
成功存进银行100元
账户余额:100
成功存进银行100元
成功取出100元
账户余额:100
账户余额:100
成功存进银行100元
成功取出100元
账户余额:100
账户余额:100
成功存进银行100元
成功取出100元
账户余额:100
账户余额:100
2.同步时的代码:
第一种:
synchronized 关键字修饰方法:
由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。
package com;
public class Bank {
private int count=0;
//存钱
public synchronized void addMoney(int money) {
count+=money;
System.out.println("成功存进银行"+money+"元");
}
public synchronized void subMoney(int money) {
if(count>=money) {
count-=money;
System.out.println("成功取出"+money+"元");
}else {
System.out.println("余额不足");
}
}
public void lookMoney() {
System.out.println("账户余额:"+count);
}
}
运行结果:
余额不足
账户余额:0
余额不足
账户余额:0
成功存进银行100元
账户余额:100
成功存进银行100元
账户余额:100
成功取出100元
账户余额:100
成功取出100元
账户余额:0
成功存进银行100元
账户余额:100
成功存进银行100元
账户余额:100
成功取出100元
账户余额:100
成功存进银行100元
账户余额:200
成功取出100元
账户余额:100
成功取出100元
账户余额:0
成功存进银行100元
账户余额:100
成功取出100元
账户余额:0
成功存进银行100元
账户余额:100
成功存进银行100元
成功取出100元
账户余额:100
账户余额:100
注意:
synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类
第二种:
synchronized关键字同步代码块:
package com;
public class Bank {
private int count=0;
//存钱
public void addMoney(int money) {
synchronized(this) {
count+=money;
}
System.out.println("成功存进银行"+money+"元");
}
public void subMoney(int money) {
synchronized(this) {
if(count>=money) {
count-=money;
System.out.println("成功取出"+money+"元");
}else {
System.out.println("余额不足");
}
}
}
public void lookMoney() {
System.out.println("账户余额:"+count);
}
}
余额不足
账户余额:0
成功存进银行100元
账户余额:100
成功取出100元
账户余额:0
成功存进银行100元
成功取出100元
账户余额:0
账户余额:0
成功存进银行100元
账户余额:0
成功取出100元
账户余额:0
3.volatile关键字
它的原理是每次要线程要访问volatile修饰的变量时都是从内存中读取,而不是从缓存当中读取,因此每个线程访问到的变量值都是一样的。这样就保证了同步。
- volatile关键字为域变量的访问提供了一种免锁机制
- 使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新
- 因此每次使用该域就要重新计算,而不是使用寄存器中的值
- volatile不会提供任何原子操作,它也不能用来修饰final类型的变量
运行结果:
余额不足
账户余额:0
余额不足
成功存进银行100元
账户余额:100
账户余额:100
成功取出100元
账户余额:100
成功存进银行100元
账户余额:100
成功取出100元
账户余额:0
成功存进银行100元
账户余额:100
成功取出100元
成功存进银行100元
账户余额:200
账户余额:200
成功存进银行100元
账户余额:200
成功取出100元
账户余额:200