synchronized
死锁
synchronized作为解决并发编程中原子性、可见性和有序性问题的万能钥匙。其带来的是性能上的问题。使用synchronized关键是看充当锁的角色,锁的作用是保护资源,我们要确定其锁定的范围囊括了需要保护的资源。我们知道synchronized(类名.class){}的用法,类名.class是一个Class的对象,只在JVM中存在一份,所以在不考虑分布式的情况下,这个用法真的可以说是“万能”的。但是通用的背后带来的是性能的问题,如现在有一个账户类(Account),如果将整个类锁定,那么当多个账户对象对账户进行操作时,必须排队进行,这显然大大降低了性能。所以,要选好充当锁的角色,最好是能精细化到一个个资源,这就是细粒度锁。但是使用细粒度锁又会带来一些其他的问题,那就是需要申请多个资源时,就会使用到多个锁,这就有可能产生死锁。
死锁的一个比较专业的定义是:一组互相竞争资源的线程因互相等待,导致“永久”阻塞的现象。下面我们通过代码来看一下发生死锁的情况。
Account.java
public class Account {
private int money;
public Account(int money) {
this.money = money;
}
public void addMoney(int num) {
money += num;
}
public boolean subMoney(int num) {
if(money >= num) {
money -= num;
return true;
}
return false;
}
public void setMoney(int money) {
this.money = money;
}
public int getMoney() {
return money;
}
}
MyThread.java
public class MyThread extends Thread {
private final Account account1;
private final Account account2;
private final int num;
public MyThread(Account account1, Account account2, int num) {
this.account1 = account1;
this.account2 = account2;
this.num = num;
}
// @Override
// public void run() {
// synchronized (account1) {
// synchronized (account2) {
// if(account1.subMoney(num)) {
// account2.addMoney(num);
// }
// }
// }
// }
@Override
public void run() {
synchronized (account1) {
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (account2) {
if(account1.subMoney(num)) {
account2.addMoney(num);
}
}
}
}
}
Test.java
public class Test {
public static void main(String[] args) throws InterruptedException {
Account account1 = new Account(1000);
Account account2 = new Account(1000);
MyThread myThread1 = new MyThread(account1, account2, 100);
MyThread myThread2 = new MyThread(account2, account1, 100);
myThread1.start();
myThread2.start();
myThread1.join();
myThread2.join();
System.out.println("账户1的余额:" + account1.getMoney() + "账户2的余额:" + account2.getMoney()