线程同步
- Java中的同步和异步
- 同步:即加锁
- Java中同步值的是不同时进行运行
- 同步:即加锁
- Java中的异步
- 异步:Java中的异步值同时进行
- 取钱案例出现问题的原因?
- 多个线程同时执行,发现账户都是够钱的。
- 如何才能保证线程安全呢?
- 让多个线程实现先后依次访问共享资源,这样就解决了安全问题
线程同步核心思想
- 加锁,把共享资源进行上锁,每次只能一个线程进入访问完毕以后解锁,然后其他线程才能进来。
- 线程同步解决安全问题的思想是什么?
- 加锁:让多个线程实现先后依次访问共享资源,这样就解决了安全问题。
方式一:同步代码块
- 同步代码块
- 作用:把出现线程安全问题的核心代码给上锁。
- 原理:每次只能一个线程进入,执行完毕后自动解锁,其他线程才可以进来执行。
- 格式:
synchronized(同步锁对象) {
操作共享资源的代码(核心代码)
}
-
锁对象要求
- 理论上:锁对象只要对于当前同时执行的线程来说是同一个对象即可。
-
锁对象用任意唯一的对象好不好呢?
- 不好,会影响其他无关线程的执行。
-
锁对象的规范要求
- 规范上:建议使用共享资源作为锁对象。
- 对于实例方法建议使用this作为锁对象。
- 对于静态方法建议使用字节码(类名.class)对象作为锁对象。
- 同步代码块是如何实现线程安全的?
- 对出现问题的核心代码使用synchronized进行加锁
- 每次只能一个线程占锁进入访问
- 同步代码块的同步锁对象有什么要求?
- 对于实例方法建议使用this作为锁对象。
- 对于静态方法建议使用字节码(类名.class)对象作为锁对象。
方式二:同步方法
- 同步方法
- 作用:把出现线程安全问题的核心方法给上锁。
- 原理:每次只能一个线程进入,执行完毕以后自动解锁,其他线程才可以进来执行。
- 格式:
修饰符 synchronized 返回值类型 方法名称(形参列表) {
操作共享资源的代码
}
- 同步方法底层原理
- 同步方法其实底层也是有隐式锁对象的,只是锁的范围是整个方法代码。
- 如果方法是实例方法:同步方法默认用this作为的锁对象。但是代码要高度面向对象!
- 如果方法是静态方法:同步方法默认用类名.class作为的锁对象。
public class MoneyTest {
public static void main(String[] args) {
Account account = new Account("20220919",100000.0);
Thread mom = new DrawMoneyThread(account);
mom.setName("mom");
Thread son = new DrawMoneyThread(account);
son.setName("son");
mom.start();
son.start();
Account account1 = new Account("20220918",100000.0);
Thread dad = new DrawMoneyThread(account1);
dad.setName("dad");
Thread daughter = new DrawMoneyThread(account1);
daughter.setName("daughter");
dad.start();
daughter.start();
}
}
class DrawMoneyThread extends Thread{
private Account account;
public DrawMoneyThread(Account account) {
this.account = account;
}
@Override
public void run() {
account.drawMoney(100000);
}
}
public class Account {
private String cardCode;
private double money;
private Object lock = new Object();
public Account() {
}
public synchronized void drawMoney(double money) {
System.out.println(Thread.currentThread().getName()+"准备取钱");
//synchronized (this) {
/*上锁
显示锁:使用this可以直接锁住当前对象 即账户Accout
隐式锁:写在方法的修饰符之后
非静态方法:但是一定要是非静态方法锁住的也是当前的对象this
静态方法:锁住的是当前的字节码(class)对象*/
if (this.money >= money) {
System.out.println(Thread.currentThread().getName() + "您当前还有:" + this.money
+ "取出" + money);
this.money -= money;
System.out.println("成功取出" + money + "余额为:" + this.money);
} else {
System.out.println("余额不足");
}
}
public Account(String cardCode, double money) {
this.cardCode = cardCode;
this.money = money;
}
public String getCardCode() {
return cardCode;
}
public void setCardCode(String cardCode) {
this.cardCode = cardCode;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
-
***上锁 ***
- ***显示锁:使用this可以直接锁住当前对象 即账户Accout ***
- ***隐式锁:写在方法的修饰符之后 ***
- ***非静态方法:但是一定要是非静态方法锁住的也是当前的对象this ***
- 静态方法:锁住的是当前的字节码(class)对象
-
是同步代码块好还是同步方法好一点?
- 同步代码块锁的范围更小,同步方法锁的范围更大。