1 Lock锁介绍
已经在【JUC基础】04简单介绍过了,本文做进一步的拓展,比如公平锁和非公平锁、
📌 明白锁的核心
四个对象:线程,共享资源,锁,锁操作
包括线程如何操作资源,使用锁锁哪个资源,锁让谁等待,谁唤醒,这是我们在加锁时需要考虑的
📌 synchronized 与Lock区别
synchronized是一个关键字,lock是一个类
synchronized自动释放锁,lock需要手动释放
synchronized线程1获得了锁进入阻塞,线程2会死等。lock不会
synchronized非公平,lock可以使用公平锁
synchronized适合锁少量代码同步问题,lock适合锁大量同步代码
📌 Lock重点
Lock接口的实现类均需要主动加锁和解锁:
主要有三个实现类,ReentrantLock最常用:
2 公平锁和非公平锁
📌 要点
公平锁:必须先来后到,十分公平
非公平锁:允许插队(默认-为了效率)
以下是ReentrantLock的构造方式👇(synchronized默认也是非公平锁)
📌 代码举例
首先在主线程中启动一个T线程,给他上锁,休眠2秒(在它释放锁之前,启动一个T1线程,T1线程中创建10个B线程,因为T已经上锁了,那么后边的A线程就必须等T1线程启动后才能获取锁,但是10个B线程已经排在了10个B线程后边),在主线程中再启动10个A线程获取锁,此时可观察公平锁和非公平锁的具体情况。
公平锁:B线程一直再A线程后边
非公平锁:B线程可能会插队到A线程前边
public class testLock {
public static void main(String[] args) throws InterruptedException {
test1(false);//非公平锁
// test1(true);//公平锁
}
public static void test1(boolean fair) throws InterruptedException {
ReentrantLock lock = new ReentrantLock(fair);
new Thread(() -> {
lock.lock();
try {
System.out.println("start");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
create10T(lock, "B");
},"T1").start();
System.out.println("end");
} finally {
lock.unlock();
}
},"T").start();
create10T(lock, "A");
}
public static void create10T(ReentrantLock lock, String threadPre) {
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(() -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+"获取到锁!");
} finally {
lock.unlock();
}
});
thread.setName(threadPre + "-" + i);
thread.start();
}
}
}
非公平锁:
公平锁:
3 Lock版的生产者消费者问题
📌 Condition 通知和唤醒线程
Condition是个接口,基本的方法就是await()和signal()方法;
Conditon中的await()对应Object的wait();
Condition中的signal()对应Object的notify();
Condition中的signalAll()对应Object的notifyAll()。
核心:锁的condition执行await,就是让该线程携带对应的condition进入等待队列,当condition执行signal就是让携带该condition的线程唤醒,使用于lock与unlock之间。
3.1 Lock处理生产者消费者问题
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockPC {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
data.plus();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
data.minus();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
data.plus();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
data.minus();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
class Data{//资源类
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
//+1
public void plus() throws InterruptedException {
lock.lock();
try {
while (number!=0){
condition.await();//等待
}
number++;
System.out.println(Thread.currentThread().getName()+"=>"+number);
condition.signalAll();//通知其他线程,+1结束
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//-1
public void minus() throws InterruptedException {
lock.lock();
try {
while (number==0){
condition.await();//等待
}
number--;
System.out.println(Thread.currentThread().getName()+"=>"+number);
condition.signalAll();//通知其他线程,-1结束
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
控制台输出:
3.2 Condition 精准通知和唤醒线程
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//A执行完调用B,B执行完调用C,C执行完调用A
public class LockCondition {
public static void main(String[] args) {
Data2 data = new Data2();
new Thread(()->{
for (int i = 0; i < 5; i++) {
data.pringtA();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 5; i++) {
data.pringtB();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 5; i++) {
data.pringtC();
}
},"C").start();
}
}
class Data2{
private Lock lock= new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
private int number = 1; //1A、2B、3C
public void pringtA(){
lock.lock();
try { //业务,判断->执行->通知
while (number!=1){
condition1.await();
}
System.out.println(Thread.currentThread().getName()+"=>"+number);
//唤醒指定的B
number = 2;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void pringtB(){
lock.lock();
try {
while (number!=2){
condition2.await();
}
System.out.println(Thread.currentThread().getName()+"=>"+number);
//唤醒指定的B
number = 3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void pringtC(){
lock.lock();
try {
while (number!=3){
condition3.await();
}
System.out.println(Thread.currentThread().getName()+"=>"+number);
//唤醒指定的B
number = 1;
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
控制台输出: