深圳网站建设黄浦网络-技术差,遵义市做网站设计公司,wordpress分类目录和标签的作用,阿里云iot网站开发死锁
1、介绍 在 Java 中使用多线程#xff0c;就会有可能导致死锁问题。死锁会让程序一直卡住#xff0c;程序不再往下执行。只能通过中止并重启的方式来让程序重新执行。要尽可能避免死锁的情况发生 2、造成死锁的原因
互斥条件#xff1a; 同一资源同时只能由一个线程读…死锁
1、介绍 在 Java 中使用多线程就会有可能导致死锁问题。死锁会让程序一直卡住程序不再往下执行。只能通过中止并重启的方式来让程序重新执行。要尽可能避免死锁的情况发生 2、造成死锁的原因
互斥条件 同一资源同时只能由一个线程读取
不可抢占条件 不能强行剥夺线程占有的资源
请求和保持条件 请求其他资源的同时对自己手中的资源保持不放
循环等待条件 在相互等待资源的过程中形成一个闭环
预防死锁 只需要破坏其中一个条件即可比如使用定时锁、尽量让线程用相同的加锁顺序加锁超时或自动释放死锁检测算法等等
3、避免死锁的方法
固定加锁的顺序(针对锁顺序死锁)开放调用(针对对象之间协作造成的死锁)使用定时锁–tryLock()如果等待获取锁时间超时则抛出异常而不是一直等待
二、顺序死锁
例子
public class ThreadTest6 {public static void main(String[] args) {Demo demo new Demo();new Thread(demo,1).start();new Thread(demo,2).start();new Thread(demo,3).start();new Thread(demo,4).start();}}class Demo implements Runnable{Account a new Account(A,1000);Account b new Account(B,1000);Overridepublic void run() {transferMoney(a,b,100);transferMoney(b,a,100);}public void transferMoney(Account fromAccount, Account toAccount,double money) {synchronized (fromAccount) {System.out.println(线程 Thread.currentThread().getName() 得到锁 fromAccount.getName());synchronized (toAccount) {System.out.println(线程 Thread.currentThread().getName() 得到锁 toAccount.getName());if(fromAccount.getMoney() money) {System.out.println(余额不足);} else {fromAccount.setMoney(fromAccount.getMoney()-money);toAccount.setMoney(toAccount.getMoney() money);System.out.println(转账后 fromAccount.getName() 有 fromAccount.getMoney());System.out.println(转账后 toAccount.getName() 有 toAccount.getMoney());}}}}
}
class Account{public Account(String name, double money) {this.name name;this.money money;}private String name;private double money;public String getName() {return name;}public void setName(String name) {this.name name;}public double getMoney() {return money;}public void setMoney(double money) {this.money money;}}代码有可能会发生死锁如果两个线程同时调用 transferMoney()线程A 从 X账户 向 Y账户 转账线程B 从 账户Y 向 账户X 转账那么就会发生死锁 避免死锁 上面 transferMoney() 发生死锁的原因是因为加锁顺序不一致而出现的如果所有线程以固定的顺序来获得锁那么程序中就不会出现锁顺序死锁问题 上面的例子改造
public class InduceLockOrder {// 额外的锁、避免两个对象hash值相等的情况(即使很少)private static final Object tieLock new Object();public void transferMoney(final Account fromAcct, final Account toAcct, final DollarAmount amount) throws InsufficientFundsException {class Helper {public void transfer() throws InsufficientFundsException {if (fromAcct.getBalance().compareTo(amount) 0)throw new InsufficientFundsException();else {fromAcct.debit(amount);toAcct.credit(amount);}}}// 得到锁的hash值int fromHash System.identityHashCode(fromAcct);int toHash System.identityHashCode(toAcct);// 根据hash值来上锁if (fromHash toHash) {synchronized (fromAcct) {synchronized (toAcct) {new Helper().transfer();}}} else if (fromHash toHash) {// 根据hash值来上锁synchronized (toAcct) {synchronized (fromAcct) {new Helper().transfer();}}} else {// 额外的锁、避免两个对象hash值相等的情况(即使很少)synchronized (tieLock) {synchronized (fromAcct) {synchronized (toAcct) {new Helper().transfer();}}}}}
}得到对应的 hash值 来固定加锁的顺序这样就不会发生死锁的问题 三、协作对象之间发生死锁
发生条件 A对象 的一个同步方法调用了 B对象 的同步方法。且有B对象 的一个同步方法调用了 A对象 的一个同步方法。则可能发生A线程 得到了 A对象 锁B对象 同时得到了 B对象 锁都不会释放且都无法继续执行就发生了死锁 开放调用避免死锁 在协作对象之间发生死锁中主要是因为在调用某个方法时就需要持有锁并且在方法内部也调用了其他带锁的方法如果在调用某个方法时不需要持有锁那么这种调用被称为开放调用可以在方法中使用同步代码块来实现同步调用另一对象的同步方法不放在同步代码块中就解决了问题 四、定时锁避免死锁
tryLock 方法 使用显式 Lock 锁在获取锁时使用 tryLock() 方法。当等待超过时限的时候tryLock() 不会一直等待而是返回错误信息 tryLock 是防止自锁的一个重要方式 tryLock() 方法是有返回值的它表示用来尝试获取锁如果获取成功则返回true如果获取失败即锁已被其他线程获取则返回false这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待 例子
public class tryLock {public static void main(String[] args) {System.out.println(开始);final Lock lock new ReentrantLock();new Thread() {Overridepublic void run() {String tName Thread.currentThread().getName();if (lock.tryLock()) {System.out.println(tName 获取到锁);} else {System.out.println(tName 获取不到锁);return;}try {for (int i 0; i 5; i) {System.out.println(tName : i);}Thread.sleep(5000);} catch (Exception e) {System.out.println(tName 出错了);} finally {System.out.println(tName 释放锁);lock.unlock();}}}.start();new Thread() {Overridepublic void run() {String tName Thread.currentThread().getName();if (lock.tryLock()) {System.out.println(tName 获取到锁);} else {System.out.println(tName 获取不到锁);return;}try {for (int i 0; i 5; i) {System.out.println(tName : i);}} catch (Exception e) {System.out.println(tName 出错了);} finally {System.out.println(tName 释放锁);lock.unlock();}}}.start();System.out.println(结束);}
}五、总结
发生死锁的原因主要由于 线程之间交错执行 解决 以固定的顺序加锁 执行某方法时就需要持有锁且不释放 解决 缩减同步代码块范围最好仅操作共享变量时才加锁 永久等待 **解决**n使用 tryLock() 定时锁超过时限则返回错误信息