同步代码块
作用:把访问共享资源的核心代码给上锁 ,以此保证线程安全
原理:每次只有允许一个线程加锁以后进入。执行完毕以后自动解锁 。
其他线才可以进来执行。同步代码的注意事项
对于当前同时执行的线程来说 ,同步锁必须是同一把 (同一个对象)否自会出bug
同步代码块上锁的方法
1、是同步代码块好还是同步方法好一点?
范围上:同步代码块锁的范围更小,同步方法锁的范围更大
同步代码块的性能好因为范围小
还有一种直接写到修饰符后面
注意
Lock锁是IDK5开始提供的一个新的锁定操作,通过它可以创建出锁对象进行加锁和解锁,更灵活、更方便、更强大
Lock是接口,不能直接实例化,可以采用它的实现类ReentrantLock来构建Lock锁对象。
创建Lock对象
调用Iock对象 加锁
解锁如果出现bug程序卡在质量
package SafetyTest;
import java.time.LocalDateTime;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Account {
private String carId; //卡号
private double money ;//余额
private final Lock lk= new ReentrantLock();
public Account() {
}
public Account(String carId, double money) {
this.carId = carId;
this.money = money;
}
public void drawMoney(double mony) {
lk.lock();
//先知道那个人来取钱
String name= Thread.currentThread().getName();
if (this.money>=mony){
System.out.println(name+"来取钱"+mony+"成功!");
this.money-=mony;
System.out.println(name+"来取钱后:剩余的“:"+this.money);
}else{
System.out.println(name+"来取钱:余额不足~~!");
}
lk.unlock();
}
public String getCarId() {
return carId;
}
public void setCarId(String carId) {
this.carId = carId;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
package SafetyTest;
public class DrawThread extends Thread {
private Account acc;
public DrawThread(Account acc, String name){
super(name);
this.acc=acc;
}
@Override
public void run() {
super.run();
//取钱
acc.drawMoney(10000);
}
}
package SafetyTest;
public class ThreadSafety {
//模拟线程安全问题
public static void main(String[] args) {
//1:创建一个账户对象 代表两个人的共享账户
Account acc=new Account("ICBC",10000);
//创建两个线程 分别两个人 再去同一个账户里取钱10000
Account acc1=new Account("ICBC",10000);
new DrawThread(acc1,"第一个人1").start(); //第1个人
new DrawThread(acc1,"第二个人2") .start(); //第2个人
new DrawThread(acc,"第一个人").start(); //第1个人
new DrawThread(acc,"第二个人").start(); //第2个人
}
}