多线程锁的总结

总结锁

公平锁与非公平锁

公平锁:非常公平,不可以插队

非公平锁:不公平,可以插队,谁能力强,把谁优先

可重入锁

什么是可重入锁?

  • 可重入锁,也被称为递归锁,它指的是在同一个线程中,当外层方法获取锁的时候,如果内层方法也需要获取同一把锁,那么内层方法会自动获取到锁,不会因为外层方法已经获取过该锁且尚未释放而导致线程阻塞

  • synchronized关键字和ReentrantLock都是典型的可重入锁实现。

  • 当线程重复获取同一个锁时,如果是不可重入锁,那么每次获取锁都需要进行线程同步,这会增加不必要的性能开销。而可重入锁则允许同一个线程多次获取同一把锁,从而避免这种不必要的开销。

  • 可重入锁还可以在一定程度上避免死锁的发生

自旋锁

public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
        var5 = this.getIntVolatile(var1, var2);
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

    return var5;
}
  • 这个就是自旋锁

  • 如果不满足条件就一直旋转,直到满足条件

  • 写一个线程自旋锁

public class MyLock {
    private static AtomicReference<Thread> atomicReference = new AtomicReference();
    Thread thread = Thread.currentThread();
    public void myLock() {
        

        //不满足线程为
        while (!atomicReference.compareAndSet(null, thread)) {
			System.out.println(Thread.currentThread().getName() + "持续获得资源");
        }
        System.out.println(Thread.currentThread().getName() + "lock");
    }


    public void myUnLock(){
        System.out.println(Thread.currentThread().getName() + "unlock");
        atomicReference.compareAndSet(thread, null);
    }


}

class Test{
    public static void main(String[] args) {
        MyLock myLock = new MyLock();
        new Thread(()->{
            myLock.myLock();
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                myLock.myUnLock();
            }
        },"a").start();



        new Thread(()->{
            myLock.myLock();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                myLock.myUnLock();
            }
        },"b").start();
    }
}
  • 创建一个原子引用,泛型是,Thread线程
  • 循环判断是,不满足线程为空,也就是线程资源没有被占用,测试是为了让每次只跑一个线程
  • 初始情况下,原子引用的的初始值是为null,
  • 所以只用是空的情况下,才会将资源分配给当前线程(Thread thread = Thread.currentThread();)
  • 那么当线程a,拿到资源时,线程b,就会进入循环,一直获取资源,知道线程a解锁

死锁

  • 当男孩拿了苹果,等他吃完苹果要吃零食

  • 女孩吃里零食,他想吃苹果

  • 男孩必须拿到零食的锁,才能全部释放

  • 女孩必须拿到苹果的锁,才能全部释放

  • 于是两个人都拿不到资源,处于死锁状态

public class DeadLock {
    public static void main(String[] args) {
        Apple apple = new Apple();
        Snack snack = new Snack();


        Boy boy = new Boy(apple,snack);
        Girl girl = new Girl(apple,snack);

        new Thread(boy).start();
        new Thread(girl).start();

    }

}

class Boy implements Runnable{
    private Apple apple;
    private Snack snack;

    public Boy(Apple apple, Snack snack) {
        this.apple = apple;
        this.snack = snack;
    }

    @Override
    public void run() {
        synchronized (apple){
            System.out.println("男孩在吃苹果");
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("男孩苹果吃完了");
            synchronized (snack){
                System.out.println("男孩在吃零食");
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("男孩零食吃完了");
            }
        }
    }
}
class Girl implements Runnable{
    private Apple apple;
    private Snack snack;

    public Girl(Apple apple, Snack snack) {
        this.apple = apple;
        this.snack = snack;
    }
    @Override
    public void run() {
        synchronized (snack){
            System.out.println("女孩在吃零食");
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("女孩零食吃完了");
            synchronized (apple){
                System.out.println("女孩在吃苹果");
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("女孩苹果吃完了");
            }
        }

    }
}

class Apple{

}
class Snack{

}

为什么可以保证不会死锁

public class ReetrantLockTest {

    public static void main(String[] args) {
        Email email = new Email();
        new Thread(()->{
            email.write();
        },"a").start();


        new Thread(() -> {
            email.write();
        },"b").start();
    }
}


class Email{

    public synchronized void write(){
        System.out.println(Thread.currentThread().getName()+"写邮件");
        send();
    }

    public synchronized void send(){
        System.out.println(Thread.currentThread().getName()+"发短信");
    }
}
  • 当出现多个线程对同一个资源操作时,就有可能出现死锁
  • 可重入锁是让线程在获得了实例锁之后,不需要再次获得锁,而是继续执行,最后释放锁
  • 当使用ReenTrantLock时,锁的时ReententLock对象
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值