多线程之死锁,活锁。

死锁的定义:
  集合中每一个进程都在等待只能由本集合中的其他进程才能引发的事件那么该进程就是死锁的。java中指的就是多个线程在竞争多个资源的时候就可能出现死锁现象。
常见的死锁
  简单顺序死锁: 如两个线程在执行不同的方法时,方法1是先锁了A然后去争取获得B,而方法2是先去锁了B再去获得锁A。这时如果有两个线程,一个线程执行了方法1,另外一个线程执行方法2的时候。这个时候就会出现死锁的情况。
代码演示:

package com.chen.springboot.thread.dlock;

public class SimpleOrderDeadLock {


    private static Object aLock = new Object();

    private static Object bLock = new Object();


    public static void getAthenB(){
        synchronized (aLock){
            System.out.println(Thread.currentThread()+"获得了aLock 开始获得bLock");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (bLock){
                System.out.println(Thread.currentThread()+"获得了bLock");
            }
        }
    }

    public static void getBthenA(){
        synchronized (bLock){

            System.out.println(Thread.currentThread()+"获得了aLock 开始获得bLock");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (aLock){
                System.out.println(Thread.currentThread()+"获得了bLock");
            }
        }
    }
    static class Athread extends Thread{
        @Override
        public void run() {
            getBthenA();
        }
    }
    static class Bthread extends Thread{
        @Override
        public void run() {
            getAthenB();
        }
    }
    public static void main(String[] args) {
        Athread a = new Athread();
        Bthread b = new Bthread();
        a.start();
        b.start();
    }
}


使用java内存分配工具可以看到两个线程都已经持有了对方的锁,而且还都在等待对方的锁

11


动态顺序死锁
相比简单殊勋死锁,可以直接修改锁对象的顺序就能够完美解决死锁的情况。但是动态顺序死锁就不一定了,比如还是两个锁对象。两个对象A和B是通过参数传递过来的时候,这个时候如果先要先锁A,再锁B.一个线程来的时候是没有问题的,但是这个时候如果两一个线程执行方法时传的参数先是B再是A的时候,还是会出现死锁。代码演示:

package com.chen.springboot.thread.dlock.impl;

import com.chen.springboot.thread.dlock.DynamicParamLock;

public class DynamicDeadLock implements DynamicParamLock {

    @Override
    public void doSomething(Object a, Object b) {
        synchronized (a){
            System.out.println(Thread.currentThread().getName()+"先拿到了的所对象是"+a);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (b){
                System.out.println("又拿到了所对象是"+b);
            }
        }
    }


    public static void main(String[] args) {
        Object a = new Object();
        Object b = new Object();
        DynamicParamLock dynamicParamLock = new DynamicDeadLock();

        Rthread r1 = new Rthread(a,b,dynamicParamLock);
        Rthread r2 = new Rthread(b,a,dynamicParamLock);
        r1.start();
        r2.start();
    }


    static class Rthread extends Thread{
        private Object a;
        private Object b;
        private DynamicParamLock paramLock;

        public Rthread(Object a, Object b, DynamicParamLock paramLock) {
            this.a = a;
            this.b = b;
            this.paramLock = paramLock;
        }
        @Override
        public void run() {
           paramLock.doSomething(a,b);
        }
    }

}


如图所示还是会出现死锁状态:

解决方法 1 将本来动态资源顺序会改变的情况改通过一种机制改成固定的顺序。
可以通过比较两个对象的hash值,判断大小来指定锁资源的顺序
 

package com.chen.springboot.thread.dlock.impl;

import com.chen.springboot.thread.dlock.DynamicParamLock;

public class DeterminOrderLock implements DynamicParamLock {

    private static Object tieLock = new Object();


    @Override
    public void doSomething(Object a, Object b) {
      //通过确定两个资源内存内部的hash值来进行加锁,
        int ahash = System.identityHashCode(a);
        int bhash = System.identityHashCode(b);
        if(ahash>bhash){
            synchronized (a){
                System.out.println(Thread.currentThread().getName()+"先拿到了锁对象为"+a);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (b){
                    System.out.println(Thread.currentThread().getName()+"拿到了锁对象"+b);
                }
            }
        }else if(ahash<bhash){
            synchronized (b){
                System.out.println(Thread.currentThread().getName()+"先拿到了锁对象为"+b);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (a){
                    System.out.println(Thread.currentThread().getName()+"先拿到了锁对象为"+a);
                }
            }
        }else{
            synchronized (tieLock){//由于hash值本身就是一个hash 映射会出现hash 碰撞的现象所以在判断完hash值的基础上在让两个线程竞争同一个资源这样就避免了hash出现的问题
                synchronized (a){
                    System.out.println(Thread.currentThread().getName()+"先拿到了锁对象为"+a);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (b){
                        System.out.println(Thread.currentThread().getName()+"拿到了锁对象"+b);
                    }
                }
            }
        }
    }
}


最终执行的结果中可以看到没有出现死锁的情况:
 

Thread-1先拿到了锁对象为java.lang.Object@d156cd4
Thread-1拿到了锁对象java.lang.Object@3d29306
Thread-0先拿到了锁对象为java.lang.Object@d156cd4
Thread-0先拿到了锁对象为java.lang.Object@3d29306



 解决方法 2 定义的对象中持有ReentranceLock ,通过ReentranceLock中的tryLock的方式来获取锁.
所需上锁的对象有一个ReentranceLock
 

package com.chen.springboot.thread.dlock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockObject {
    private final Lock lock = new ReentrantLock();
    public Lock getLock() {
        return lock;
    }
}



执行方法的时候调用lock.tryLock方法来实现
 

package com.chen.springboot.thread.dlock.impl;

import com.chen.springboot.thread.dlock.DynamicParamLock;
import com.chen.springboot.thread.dlock.LockObject;

import java.util.Random;

public class UserReentranceLock implements DynamicParamLock {
    @Override
    public void doSomething(Object a, Object b) {
        LockObject aLock = (LockObject)a;
        LockObject bLock = (LockObject)b;
        Random r = new Random();
        while (true){
            if(aLock.getLock().tryLock()){
                try {
                    System.out.println(Thread.currentThread().getName()+"获得的锁资源为"+aLock);
                    if(bLock.getLock().tryLock()){
                        try {
                            System.out.println(Thread.currentThread().getName()+"获得的锁资源"+bLock);
                            break;
                        }finally {
                            bLock.getLock().unlock();
                        }
                    }
                }finally {
                    aLock.getLock().unlock();
                }
            }  
        }
    }
}


但是通过这种当时调用的时候存在活锁的情况
 

Thread-1获得的锁资源为com.chen.springboot.thread.dlock.LockObject@7a024d7
Thread-0获得的锁资源为com.chen.springboot.thread.dlock.LockObject@61a09c6b
Thread-1释放了锁资源com.chen.springboot.thread.dlock.LockObject@7a024d7
Thread-0释放了锁资源com.chen.springboot.thread.dlock.LockObject@61a09c6b
Thread-1获得的锁资源为com.chen.springboot.thread.dlock.LockObject@7a024d7
Thread-0获得的锁资源为com.chen.springboot.thread.dlock.LockObject@61a09c6b
Thread-1释放了锁资源com.chen.springboot.thread.dlock.LockObject@7a024d7
Thread-0释放了锁资源com.chen.springboot.thread.dlock.LockObject@61a09c6b
Thread-1获得的锁资源为com.chen.springboot.thread.dlock.LockObject@7a024d7
Thread-0获得的锁资源为com.chen.springboot.thread.dlock.LockObject@61a09c6b
Thread-1释放了锁资源com.chen.springboot.thread.dlock.LockObject@7a024d7
Thread-0释放了锁资源com.chen.springboot.thread.dlock.LockObject@61a09c6b
Thread-1获得的锁资源为com.chen.springboot.thread.dlock.LockObject@7a024d7
Thread-0获得的锁资源为com.chen.springboot.thread.dlock.LockObject@61a09c6b
Thread-1释放了锁资源com.chen.springboot.thread.dlock.LockObject@7a024d7
Thread-0释放了锁资源com.chen.springboot.thread.dlock.LockObject@61a09c6b
Thread-1获得的锁资源为com.chen.springboot.thread.dlock.LockObject@7a024d7
Thread-0获得的锁资源为com.chen.springboot.thread.dlock.LockObject@61a09c6b
Thread-1释放了锁资源com.chen.springboot.thread.dlock.LockObject@7a024d7
Thread-0释放了锁资源com.chen.springboot.thread.dlock.LockObject@61a09c6b
Thread-0获得的锁资源为com.chen.springboot.thread.dlock.LockObject@61a09c6b
Thread-0获得的锁资源com.chen.springboot.thread.dlock.LockObject@7a024d7
Thread-0释放了锁资源com.chen.springboot.thread.dlock.LockObject@7a024d7
Thread-0释放了锁资源com.chen.springboot.thread.dlock.LockObject@61a09c6b
Thread-1获得的锁资源为com.chen.springboot.thread.dlock.LockObject@7a024d7
Thread-1获得的锁资源com.chen.springboot.thread.dlock.LockObject@61a09c6b
Thread-1释放了锁资源com.chen.springboot.thread.dlock.LockObject@61a09c6b
Thread-1释放了锁资源com.chen.springboot.thread.dlock.LockObject@7a024d7


通过打印出来的信息可以看出两个线程,要么同时获得了锁资源,要么同时释放了锁资源。直到最后的时候Thread0才实现了获得第一个锁资源之后,又获得了第二个锁资源才能够最终完成。
活锁的定义: 多个线程在获取锁的时候,再同时为了获取另外一个锁的时候发现锁已经被其他线程占有,这是持有锁的线程会去释放该锁,然后再去重新获取该锁,这个过程就称为活锁反复地去获取和释放锁的过程。
解决方式 添加一个阻塞在while(true)方法最后添加Thread.sleep(10)即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值