标签:alt add get print cte cond The == pre
1.大纲
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.
标签:alt add get print cte cond The == pre
原文地址:https://www.cnblogs.com/juncaoit/p/13022440.html