两个人去取钱,已知卡里余额100000,每人都要取10000
package org.example;
import java.util.Date;
public class ThreadTest {
public static void main(String[] args) {
final Account account = new Account("ICBC",100000);
//创建两个线程
new DeawThread(account,"1号").start();
new DeawThread(account,"2号").start();
}
}
package org.example;
public class DeawThread extends Thread{
private Account account;
public DeawThread(Account account,String name){
super(name);
this.account = account;
}
public void run(){
account.drawMoney(100000);
}
}
package org.example;
public class Account {
private String cardId;
private double money;
public String getCardId() {
return cardId;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public Account(String cardId, double money) {
this.cardId = cardId;
this.money = money;
}
public Account() {
}
public void drawMoney(double money) {
//获取当前线程名称
final String name = Thread.currentThread().getName();
//判断余额是否足够
if(this.money >=money){
System.out.println(name+"来取钱"+money+"成功");
this.money-=money;
System.out.println(name+"取钱后余额:"+this.money);
}else{
System.out.println(name+"来取钱,余额不足");
}
}
}
上面执行结果显然是不对的,如何解决?
一.同步代码块
作用:把访问共享资源的核心代码上锁来保证线程安全
synchronized(同步锁){
访问共享资源的核心代码
}
原理:每次只允许一个线程加锁后进入,执行完毕后解锁,其他线程才能够进入
注意事项:对于当前同时执行的线程来说,同步锁必须是同一把
我们只需要给Account类中取现代码放在同步代码块中
1.代码
public void drawMoney(double money) {
//获取当前线程名称
final String name = Thread.currentThread().getName();
//判断余额是否足够,this代表共享资源
synchronized (this) {
if(this.money >=money){
System.out.println(name+"来取钱"+money+"成功");
this.money-=money;
System.out.println(name+"取钱后余额:"+this.money);
}else{
System.out.println(name+"来取钱,余额不足");
}
}
}
2.结果
对于两个账户各取各卡的钱
3.代码
package org.example;
import java.util.Date;
public class ThreadTest {
public static void main(String[] args) {
final Account account = new Account("ICBC111",100000);
//创建两个线程
new DeawThread(account,"1号").start();
new DeawThread(account,"2号").start();
final Account account1 = new Account("ICBC112",200000);
//创建两个线程
new DeawThread(account1,"3号").start();
new DeawThread(account1,"4号").start();
}
}
package org.example;
public class Account {
private String cardId;
private double money;
public String getCardId() {
return cardId;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public Account(String cardId, double money) {
this.cardId = cardId;
this.money = money;
}
public Account() {
}
public void drawMoney(double money) {
//获取当前线程名称
final String name = Thread.currentThread().getName();
//判断余额是否足够
synchronized (this) {
if(this.money >=money){
System.out.println(name+"来取钱"+money+"成功");
this.money-=money;
System.out.println(name+"取钱后余额:"+this.money);
}else{
System.out.println(name+"来取钱,余额不足");
}
}
}
}
package org.example;
public class DeawThread extends Thread{
private Account account;
public DeawThread(Account account,String name){
super(name);
this.account = account;
}
public void run(){
account.drawMoney(100000);
}
}
4.结果
5.对于静态方法
public static void test(){
synchronized (Account.class){
//用类名.class
}
}
二.同步方法
修饰符 synchronized 返回类型 方法名称(形参列表){
共享资源代码
}
1.代码
public synchronized void drawMoney(double money) {
//获取当前线程名称
final String name = Thread.currentThread().getName();
//判断余额是否足够
if(this.money >=money){
System.out.println(name+"来取钱"+money+"成功");
this.money-=money;
System.out.println(name+"取钱后余额:"+this.money);
}else{
System.out.println(name+"来取钱,余额不足");
}
}
三.LOCK锁
Lock锁是DK5开始提供的一个新的锁定操作,通过它可以创建出锁对象进行加锁和解锁,更灵活、更方便、更强大。
Lock是接口,不能直接实例化,可以采用它的实现类ReentrantLock来构建Lock锁对象。
1.代码
private final Lock lk = new ReentrantLock();
public void drawMoney(double money) {
//获取当前线程名称
final String name = Thread.currentThread().getName();
lk.lock();
try {
//判断余额是否足够
if(this.money >=money){
System.out.println(name+"来取钱"+money+"成功");
this.money-=money;
System.out.println(name+"取钱后余额:"+this.money);
}else{
System.out.println(name+"来取钱,余额不足");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lk.unlock();
}
}