【Java开发】JUC进阶 01:Lock锁详解

本文深入介绍了Java中的Lock接口及其实现,如ReentrantLock,对比了synchronized的关键字特性。讨论了公平锁和非公平锁的概念,展示了它们在实际代码中的应用。同时,通过生产者消费者问题的示例,阐述了Condition在精确线程通知和唤醒中的作用。
摘要由CSDN通过智能技术生成

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();
        }
    }
}

控制台输出:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尹煜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值