锁的总结
Posted juncaoit
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了锁的总结相关的知识,希望对你有一定的参考价值。
1.大纲
Lock接口
锁的分类
乐观锁和悲观锁
可重入锁与非可重入锁
公平锁与非公平锁
共享锁与排它锁
自旋锁与阻塞锁
可中断锁
锁优化
一:Lock接口
1.锁
是一种工具,用于控制对共享资源的访问
Lock和synchronized,是常见的锁,都可以达到线程安全的目的
Lock最常见的实现类是ReenTrantLock
2.为啥用Lock
synchronized不够用
效率低:锁的释放情况少,试图获得锁时不能设定超时,不能中断一个正在尝试获得锁的线程
不够灵活:加锁与释放锁单一,每个锁仅有单一的条件
无法知道是否成功获取锁
3.Lock的主要方法
lock()
tryLock()
tryLock(long time, TimeUnit unit)
lockInterruptibly()
4.lock
获取最普通的获取锁,如果被其他线程获取,则进行等待
不会像synchronized一样在异常的时候自动释放锁
lock方法不能被中断,一旦陷入死锁,lock就会永久等待
package com.jun.juc.lock.lock; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Lock必须手动释放锁 */ public class MustUnLock { private static Lock lock = new ReentrantLock(); public static void main(String[] args) { lock.lock(); try{ // System.out.println(Thread.currentThread().getName()+"-run"); }finally { lock.unlock(); } } }
5.tryLock
用来尝试获取锁,如果被其他线程占用,则获取成功,返回true,否则返回false,代表获取锁失败
功能比lock强大了,可以根据是否获取到锁,决定后续程序的行为
立刻返回
6.tryLock(long time, TimeUnit unit)
超时就放弃
可以避免死锁
package com.jun.juc.lock.lock; import java.util.Random; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * tryLock避免死锁 */ public class TryLockDeadLock implements Runnable { int flag = 1; static Lock lock1 = new ReentrantLock(); static Lock lock2 = new ReentrantLock(); public static void main(String[] args) { TryLockDeadLock tryLockDeadLock1 = new TryLockDeadLock(); TryLockDeadLock tryLockDeadLock2 = new TryLockDeadLock(); tryLockDeadLock1.flag = 1; tryLockDeadLock2.flag = 0; new Thread(tryLockDeadLock1).start(); new Thread(tryLockDeadLock2).start(); } @Override public void run() { if (flag == 1) { try { for (int i = 0; i < 100; i++) { if (lock1.tryLock(800, TimeUnit.MILLISECONDS)) { try { System.out.println("1获取了lock1"); Thread.sleep(new Random().nextInt(1000)); // 获取第二把锁 if (lock2.tryLock(800, TimeUnit.MILLISECONDS)) { try { System.out.println("1获取了lock2"); System.out.println("1成功获取两把锁"); break; } finally { lock2.unlock(); Thread.sleep(new Random().nextInt(1000)); } } else { System.out.println("1获取lock2失败,在重试"); } } finally { // 因为上面获取到了锁,需要释放 lock1.unlock(); Thread.sleep(new Random().nextInt(1000)); } } else { System.out.println("1获取lock1失败,在重试"); } } } catch (Exception e) { // 防止800ms内被中断 e.printStackTrace(); } } if (flag == 0) { try { for (int i = 0; i < 100; i++) { if (lock2.tryLock(3000, TimeUnit.MILLISECONDS)) { try { System.out.println("2获取了lock2"); Thread.sleep(new Random().nextInt(1000)); // 获取第二把锁 if (lock1.tryLock(800, TimeUnit.MILLISECONDS)) { try { System.out.println("2获取了lock1"); System.out.println("2成功获取两把锁"); break; } finally { lock1.unlock(); Thread.sleep(new Random().nextInt(1000)); } } else { System.out.println("2获取lock1失败,在重试"); } } finally { // 因为上面获取到了锁,需要释放 lock2.unlock(); Thread.sleep(new Random().nextInt(1000)); } } else { System.out.println("2获取lock2失败,在重试"); } } } catch (Exception e) { // 防止800ms内被中断 e.printStackTrace(); } } } }
效果:
Connected to the target VM, address: ‘127.0.0.1:57057‘, transport: ‘socket‘ 1获取了lock1 2获取了lock2 1获取lock2失败,在重试 2获取了lock1 2成功获取两把锁 1获取了lock1 1获取了lock2 1成功获取两把锁 Disconnected from the target VM, address: ‘127.0.0.1:57057‘, transport: ‘socket‘
7.lockInterruptipy
把超时时间设置为无限,在过程中,线程可以被中断
package com.jun.juc.lock.lock; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockInterruptibly implements Runnable { private Lock lock = new ReentrantLock(); public static void main(String[] args) { LockInterruptibly lockInterruptibly = new LockInterruptibly(); Thread thread = new Thread(lockInterruptibly); Thread thread1 = new Thread(lockInterruptibly); thread.start(); thread1.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt(); } @Override public void run() { System.out.println(Thread.currentThread().getName()+"尝试获取锁"); try{ lock.lockInterruptibly(); try { System.out.println(Thread.currentThread().getName()+"拿到了锁"); Thread.sleep(5000); }catch (Exception e){ System.out.println("睡眠时间被打断"); }finally { lock.unlock(); System.out.println(Thread.currentThread().getName()+"释放了锁"); } }catch (Exception e){ System.out.println("等待锁时被打断"); e.printStackTrace(); } } }
效果:
Connected to the target VM, address: ‘127.0.0.1:62438‘, transport: ‘socket‘ Thread-0尝试获取锁 Thread-1尝试获取锁 Thread-0拿到了锁 睡眠时间被打断 Thread-0释放了锁 Thread-1拿到了锁 Disconnected from the target VM, address: ‘127.0.0.1:62438‘, transport: ‘socket‘ Thread-1释放了锁 Process finished with exit code 0
8.可见性
happens-before
lock拥有可见性保障的
二:锁的分类
1.分类
2.悲观锁的劣势
也叫互斥同步锁
劣势:
阻塞和唤醒带来的性能劣势
永久阻塞,如果持有锁的线程被永久阻塞,那么等待该线程释放的线程,永远都得不到执行
优先级反转
3.悲观锁
4.乐观锁
典型的案例就是原子类,并发容器等
5.
以上是关于锁的总结的主要内容,如果未能解决你的问题,请参考以下文章