Java Lock 接口
文章目录
JDK5加入,与synchronized比较,显示定义,结构更灵活。提供更多实用性方法,功能更强大、性能更优越。
常用方法
- void lock() //获取锁,如锁被占用,则等待。
- boolean tryLock() //尝试获取锁(成功返回true。失败返回false,不阻塞)
- void unlock() //释放锁
Lock 接口的实现类
ReentrantLock - 重入锁
Lock接口的实现类,与synchronized一样具有互斥锁功能。
eg:
窗口卖票问题
TestReentrantLock:
package StageOne.day21.demo01;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author 胡昊龙
* @version 1.0
* @description: TODO
* @date 2024/1/16 9:22
*/
public class TestReentrantLock {
public static void main(String[] args) {
//使用ReentrantLock实现线程同步
//1.创建线程池
ExecutorService es = Executors.newCachedThreadPool();
//2.提交任务
Runnable ticket = new Runnable() {
private int count = 1000;
//创建重入锁
private Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
//上锁
lock.lock();
try {
if (count<=0) {
break;
}
System.out.println(
Thread.currentThread().getName()+"卖了第"+count+"张票"
);
count--;
} finally {
//解锁
lock.unlock();
}
}
}
};
for (int i = 0; i < 4; i++) {
es.submit(ticket);
}
//3.关闭线程池
es.shutdown();
}
}
ReadWriteLock接口 - 读写锁
ReentrantReadWriteLock 实现类
- 一种支持一写多读的同步锁,读写分离,可分别分配读锁、写锁。
- 支持多次分配读锁,使多个读操作可以并发执行。
互斥规则
- 写-写:互斥,阻塞。
- 读-写:互斥,读阻塞写、写阻塞读。
- 读-读:不互斥、不阻塞。
在读操作远远高于写操作的环境中,可在保障线程安全的情况下,提高运行效率。
eg:
public class TestReentrantReadWriteLock {
public static void main(String[] args) {
ReadWrite rw = new ReadWrite();
ExecutorService es = Executors.newCachedThreadPool();
//提交任务
long start = System.currentTimeMillis();
for (int i = 0; i < 18; i++) {
es.submit(new Runnable() {
@Override
public void run() {
rw.read();
}
});
}
for (int i = 0; i < 2; i++) {
es.submit(new Runnable() {
@Override
public void run() {
rw.write(new Random().nextInt(100));
}
});
}
es.shutdown();
//直到线程中任务全部完成, 再执行后续操作
while (!es.isTerminated());
long end = System.currentTimeMillis();
System.out.println("用时:"+(end-start));
}
static class ReadWrite {
private int value;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
public void write(int value) {
//上写锁
lock.writeLock().lock();
this.value = value;
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"写入..."+value);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
//解锁
lock.writeLock().unlock();
}
}
public void read() {
//上读锁
lock.readLock().lock();
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"读取..."+value);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.readLock().unlock();
}
}
}
}
Condition-条件队列
Condition接口也提供了类似Object的监视器方法,与Lock配合可以实现等待/通知模式。
Condition可以通俗的理解为条件队列。当一个线程在调用了await方法以后进入等待队列,直到线程等待的某个条件为真的时候才会被唤醒。
方法名 | 描述 |
---|---|
await() | 当前线程进入等待状态 |
signal() | 唤醒一个等待线程 |
signalAll() | 唤醒所有等待线程 |
面试题:
需求:使用Lock和Condition实现三个线程交替输出20遍“ABC”
Alternative:
package StageOne.day21.demo01.TestAlter;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author 胡昊龙
* @version 1.0
* @description: TODO
* @date 2024/1/16 11:19
*/
public class Alternative {
private final Lock lock = new ReentrantLock();
private final Condition conditionA = lock.newCondition();
private final Condition conditionB = lock.newCondition();
private final Condition conditionC = lock.newCondition();
/**
* 1,2,3 控制 该打印哪个字母
*/
private int num = 1;
public void printA() {
lock.lock();
try {
if (num != 1) {
conditionA.await();
}
System.out.print("A ");
num=2;
conditionB.signal();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
if (num != 2) {
conditionB.await();
}
System.out.print("B ");
num=3;
conditionC.signal();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {
if (num != 3) {
conditionC.await();
}
System.out.println("C");
System.out.println("--------");
num=1;
conditionA.signal();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
}
Test:
package StageOne.day21.demo01.TestAlter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author 胡昊龙
* @version 1.0
* @description: TODO
* @date 2024/1/16 11:25
*/
public class Test {
public static void main(String[] args) {
Alternative alternative = new Alternative();
ExecutorService es = Executors.newCachedThreadPool();
es.submit(() -> {
for (int i = 0; i < 20; i++) {
alternative.printA();
}
});
es.submit(() -> {
for (int i = 0; i < 20; i++) {
alternative.printB();
}
});
es.submit(() -> {
for (int i = 0; i < 20; i++) {
alternative.printC();
}
});
es.shutdown();
}
}
synchronized和Lock区别
类别 | synchronized | Lock |
---|---|---|
存在层次 | Java的关键字,在JVM层面上 | 是一个接口、类 |
锁释放 | 1、获取锁的线程执行完同步代码,释放锁 2、线程执行发生异常,JVM会让线程释放锁 | 在finally中必须释放锁,不然容易造成线程死锁。 |
锁的获取 | 假设A线程获得锁,B线程等待。 如果A线程阻塞,B线程会一直等待 | Lock可以尝试获得锁,线程可以不用一直等待。 |
锁状态 | 无法判断 | 可以判断 |
锁类型 | 可重入、不可中断、非公平 | 可重入、可中断、可公平或非公平 |