在 jdk1.5 之后,并发包中新增了 Lock 接口(以及相关实现类)用来实现锁功能,Lock 接口提供了与 synchronized 关键字类似的同步功能,但需要在使用时手动获取锁和释放锁。
Lock 锁与 synchronized 同步锁的区别
lock锁:手动挡,手动上锁,手动释放锁,灵活性高
synchronized同步锁:自动挡,代码开始自动上锁,代码结束自动释放锁,缺点效率低、扩展不高、不能自定义
Lock 接口可以尝试非阻塞地获取锁当前线程尝试获取锁。如果这一时刻锁没有被其他线程获取到,则成功获取并持有锁。
Lock 接口能被中断地获取锁 与 synchronized 不同,获取到锁的线程能够响应中断,当获取到的锁的线程被中断时,中断异常将会被抛出,同时锁会被释放。
Lock 接口在指定的截止时间之前获取锁,如果截止时间到了依旧无法获取锁,则返回。
Lock写法
Lock lock = new ReentrantLock();
lock.lock();
try{
//可能会出现线程安全的操作
}finally{
//一定在finally中释放锁
//也不能把获取锁在try中进行,因为有可能在获取锁的时候抛出异常
lock.ublock();
}
Condition用法
Condition的功能类似于在传统的线程技术中的,Object.wait()和Object.notify()的功能。
Condition condition = lock.newCondition();
res. condition.await(); 类似wait
res. Condition. Signal() 类似notify
代码示例:(可以对比着上一篇文章看,很明显的区别)
package com.Thread.test;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Res {
public String name;
public String sex;
//线程通讯标识, true表示生产者等待消费者消费后再创建,false表示消费者等待生产者生产后再消费
public boolean flag = false;
public ReentrantLock lock = new ReentrantLock();
public Condition newCondition = lock.newCondition();
}
class InThread extends Thread {
Res res;
public InThread(Res r) {
this.res = r;
}
@Override
public void run() {
int i = 0;
while (true) {
try {
res.lock.lock();
if (res.flag) {
try {
res.newCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (i == 0) {
res.name = "吕布";
res.sex = "男";
} else {
res.name = "貂蝉";
res.sex = "女";
}
i = (i + 1) % 2;
res.flag = true;
res.newCondition.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
res.lock.unlock();
}
}
}
}
class OutThread extends Thread {
Res res;
public OutThread(Res r) {
this.res = r;
}
@Override
public void run() {
while (true) {
try {
res.lock.lock();
if (!res.flag) {
try {
res.newCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(res.name + "--" + res.sex);
res.flag = false;
res.newCondition.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
res.lock.unlock();
}
}
}
}
class Main {
public static void main(String[] args) {
//同一个资源
Res res = new Res();
//生产者线程
new InThread(res).start();
//消费者线程
new OutThread(res).start();
}
}
运行结果: