Java多线程技术三:锁的使用——使用ReentrantLock类-2

接上篇:Java多线程技术三:锁的使用------使用ReentrantLock类-1

9 公平锁与非公平锁

公平锁采用先到先得的策略,每次获取锁之前都会检查队列里面有没有排队等待的线程,如果没有才会尝试获取锁,如果有就将当前线程追加到队列中。

非公平锁采用"有机会插队"的策略,一个线程获取锁之前,要先去尝试获取锁,而不是在队列中等待,如果成功获取锁,说明线程虽然是后启动的,但先获得了锁,这就是"插队"效果,如果获取锁没有成功,那么将自己追加到队列中进行等待。

java 复制代码
public class MyService {
    public Lock lock;
    
    public MyService(boolean fair){
        lock = new ReentrantLock();
    }
    
    public void testMethod(){
        try {
            lock.lock();
            System.out.println("testMethod 方法的线程名 = " + Thread.currentThread().getName());
            Thread.sleep(500);
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    
}
java 复制代码
public class MyThread extends Thread{
    private MyService service;

    public MyThread(MyService service) {
        this.service = service;
    }
    
    @Override
    public void run(){
        service.testMethod();
    }
}

创建公平锁测试的运行类

java 复制代码
public class Run1 {
    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService(true);
        MyThread[] arr1 = new MyThread[10];
        MyThread[] arr2 = new MyThread[10];
        for (int i = 0; i < arr1.length; i++) {
            arr1[i] = new MyThread(service);
            arr1[i].setName("arr1+++"+(i+1));
        }
        for (int i = 0; i < arr1.length; i++) {
            arr1[i].start();
        }
        for (int i = 0; i < arr2.length; i++) {
            arr2[i] = new MyThread(service);
            arr2[i].setName("arr2---"+(i+1));
        }
        Thread.sleep(500);
        for (int i = 0; i < arr2.length; i++) {
            arr2[i].start();
        }
    }
}

打印的结果是arr1+++在前,arr2---在后,说明arr2---没有任何机会抢到锁,这就是公平锁的特点。

下面创建非公平锁测试的运行类

java 复制代码
public class Run2 {
    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService(false);
        MyThread[] arr1 = new MyThread[20];
        MyThread[] arr2 = new MyThread[20];
        for (int i = 0; i < arr1.length; i++) {
            arr1[i] = new MyThread(service);
            arr1[i].setName("arr1+++"+(i+1));
        }
        for (int i = 0; i < arr1.length; i++) {
            arr1[i].start();
        }
        for (int i = 0; i < arr2.length; i++) {
            arr2[i] = new MyThread(service);
            arr2[i].setName("arr2---"+(i+1));
        }
        Thread.sleep(500);
        for (int i = 0; i < arr2.length; i++) {
            arr2[i].start();
        }
    }
}

在多次运行程序后,使用非公平锁又看见额能在第2次arr2---,说明启动的线程先抢到锁,这就是非公平锁的特点。

10 getHoldCount()方法

public int getHoldCount()方法的作用是查询"当前线程"保持此锁定的个数,也就是调用lock()方法的次数。

java 复制代码
public class MyService {
    private ReentrantLock lock = new ReentrantLock(true);
    public void testMethod1(){
        System.out.println("A" + lock.getHoldCount());
        lock.lock();
        System.out.println("B" + lock.getHoldCount());
        testMethod2();
        System.out.println("F" + lock.getHoldCount());
        lock.unlock();
        System.out.println("G" + lock.getHoldCount());
    }

    public void testMethod2(){
        System.out.println("C" + lock.getHoldCount());
        lock.lock();
        System.out.println("D" + lock.getHoldCount());
        lock.unlock();
        System.out.println("E" + lock.getHoldCount());
    }
}
java 复制代码
public class Run1 {
    public static void main(String[] args) {
        MyService service = new MyService();
        service.testMethod1();
    }
}

执行lock方法进行锁重入,导致count计数加1的效果,执行unlock方法会使count呈减1的效果。

11 getQueueLength()方法

public final int getQueueLength()方法 的作用是返回正等待获取此锁线程的估计数,比如有5个线程,1个线程长时间占有锁,那么在调用getQueueLength()方法后的返回值是4,说明有4个线程同时在等待锁的释放。

java 复制代码
public class Service {
    public ReentrantLock lock = new ReentrantLock();
    public void serviceMethod1(){
        try {
            lock.lock();
            System.out.println("ThreadName = " +Thread.currentThread().getName());
            Thread.sleep(Integer.MAX_VALUE);
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}
java 复制代码
public class Run1 {
    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.serviceMethod1();
            }
        };
        Thread[] threads = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threads[i] = new Thread(runnable);
        }
        for (int i = 0; i < 10; i++) {
            threads[i].start();
        }
        Thread.sleep(2000);
        System.out.println("有线程数 :" + service.lock.getQueueLength() + "在等待获取锁");

    }
}

12 getWaitQueueLength(Condition condition)方法

public int getWaitQueueLength(Condition condition)方法的所用是返回等待与此锁相关的给定条件Condition的线程估计数,比如有5个线程,每个线程都执行了同一个Condition对象的await方法,则调用getWaitQueueLength方法的返回值是5。

java 复制代码
public class Service {
    private ReentrantLock lock = new ReentrantLock();
    private Condition newCondition = lock.newCondition();
    public void waitMethod(){
        try {
            lock.lock();
            newCondition.await();
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    
    public void notifyMethod(){
        try {
            lock.lock();
            System.out.println("有"+lock.getWaitQueueLength(newCondition) + "个线程正在等待newCondition");
            newCondition.signal();
        }finally {
            lock.unlock();
        }
    }
    
}
java 复制代码
public class Run1 {
    public static void main(String[] args) throws InterruptedException {
        final  Service service = new Service();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.waitMethod();
            }
        };
        Thread[] threads = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threads[i] = new Thread(runnable);
        }
        for (int i = 0; i < 10; i++) {
            threads[i].start();
        }
        Thread.sleep(2000);
        service.notifyMethod();
    }
}

13 hasQueueThread(Thread thread)方法

public final boolean hasQueueThread(Thread thread)方法的作用是查询指定的线程是否正在等待获取此锁,也就是判断参数中的线程是否在等待队列中。

java 复制代码
public class Service {
    public ReentrantLock lock = new ReentrantLock();
    public Condition condition = lock.newCondition();
    public void waitMethod(){
        try {
            lock.lock();
            Thread.sleep(Integer.MAX_VALUE);
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}
java 复制代码
public class Run1 {
    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.waitMethod();
            }
        };
        Thread a = new Thread(runnable);
        a.start();
        Thread.sleep(500);
        Thread b = new Thread(runnable);
        b.start();
        Thread.sleep(500);
        System.out.println(service.lock.hasQueuedThread(a));
        System.out.println(service.lock.hasQueuedThread(b));
    }
}

14 isLocked()方法

public boolean isLocked()方法的作用是查询此锁定是否由任意线程持有。

java 复制代码
public class Service {
    private ReentrantLock lock = new ReentrantLock();
    public void serviceMethod(){
        try {
            System.out.println(lock.isLocked());
            lock.lock();
            System.out.println(lock.isLocked());
        }finally {
            lock.unlock();
        }
    }
}
java 复制代码
public class Run1 {
    public static void main(String[] args) {
        final Service service = new Service();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.serviceMethod();
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();
    }
}

15 lockInterruptibly()方法

public void lockInterruptibly()方法的作用是当某个线程尝试获得锁并且阻塞在lock-Interruptibly()方法时,该线程可以被中断。

java 复制代码
public class MyService {
    private ReentrantLock lock = new ReentrantLock();
    public void testMethod() throws InterruptedException {
        lock.lockInterruptibly();
        System.out.println("开始执行 testMethod方法,线程名= " + Thread.currentThread().getName()+ ";执行时间 = " + Utils.data(System.currentTimeMillis()));
        for (int i = 0; i < Integer.MAX_VALUE / 10; i++) {
            String s = new String();
            Math.random();
            Thread.currentThread().yield();
        }
        System.out.println("执行完毕 testMethod方法,线程名=" + Thread.currentThread().getName()+ ";执行时间 = " + Utils.data(System.currentTimeMillis()));
        lock.unlock();
    }
}
java 复制代码
public class ThreadA extends Thread{
    private MyService service;

    public ThreadA(MyService service) {
        this.service = service;
    }
    @Override
    public void run(){
        try {
            service.testMethod();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
java 复制代码
public class Run1 {
    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();
        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();
        Thread.sleep(500);
        ThreadA b = new ThreadA(service);
        b.setName("B");
        b.start();
        Thread.sleep(500);
        b.interrupt();
        System.out.println("main中断b,但并没有成功");
    }
}

16 tryLock()方法

public boolean tryLock()方法的作用是嗅探拿锁,如果当前线程发现锁被其他线程持有了,则返回false,那么程序继续执行后面的代码,而不是呈阻塞等待锁的状态。

java 复制代码
public class MyService {
    public ReentrantLock lock = new ReentrantLock();
    public void waitMethod(){
        if(lock.tryLock()){
            System.out.println(Thread.currentThread().getName() + "获得锁");
        }else {
            System.out.println(Thread.currentThread().getName() + "没有获得锁");
        }
    }
}
java 复制代码
public class Run1 {
    public static void main(String[] args) {
        final MyService service = new MyService();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.waitMethod();
            }
        };
        Thread a = new Thread(runnable);
        a.setName("A");
        a.start();
        Thread b = new Thread(runnable);
        b.setName("B");
        b.start();
    }
}

17 实现线程按顺序执行业务

java 复制代码
public class MyService {
    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    volatile private int nextWhoPrint = 1;

    public void testMethod1(){
        try {
            lock.lock();
            while(nextWhoPrint != 1){
                condition.await();
            }
            System.out.println("AAA");
            nextWhoPrint = 2;
            condition.signalAll();
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void testMethod2(){
        try {
            lock.lock();
            while(nextWhoPrint != 2){
                condition.await();
            }
            System.out.println("   BBB");
            nextWhoPrint = 3;
            condition.signalAll();
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void testMethod3(){
        try {
            lock.lock();
            while(nextWhoPrint != 3){
                condition.await();
            }
            System.out.println("       CCC");
            nextWhoPrint = 1;
            condition.signalAll();
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}
java 复制代码
public class ThreadA extends Thread{
    private MyService service;

    public ThreadA(MyService service) {
        this.service = service;
    }
    @Override
    public void run(){
        service.testMethod1();
    }
}
java 复制代码
public class ThreadB extends Thread{
    private MyService service;

    public ThreadB(MyService service) {
        this.service = service;
    }
    @Override
    public void run(){
        service.testMethod2();
    }
}
java 复制代码
public class ThreadC extends Thread{
    private MyService service;

    public ThreadC(MyService service) {
        this.service = service;
    }
    @Override
    public void run(){
        service.testMethod3();
    }
}
java 复制代码
public class Run1 {
    public static void main(String[] args) {
        MyService service = new MyService();
        for (int i = 0; i < 5; i++) {
            ThreadA a = new ThreadA(service);
            a.start();
            ThreadB b = new ThreadB(service);
            b.start();
            ThreadC c = new ThreadC(service);
            c.start();

        }
    }
}
相关推荐
脚踏实地皮皮晨16 分钟前
003003002_WPF Grid 基类官方类定义逐行深度解析
开发语言·windows·算法·c#·wpf·visual studio
xieliyu.16 分钟前
Java 线程池入门详解:线程池基础定义 + ThreadPoolExecutor 全参构造方法逐参数解析
java·开发语言·idea·javaee
一条泥憨鱼19 分钟前
【从0开始学习计算机网络】| HTTP方法疑点解析
开发语言·计算机网络·http
老白干2 小时前
jjwt 0.9.1 在 JDK 11+ 上的两个“坑”与完整解决方案
java·python·log4j
圆山猫9 小时前
[Virtualization](四):Linux KVM/RISC-V 的 vCPU 运行路径
java·linux·risc-v
微学AI9 小时前
一根针指向所有方向:挂谷猜想对 LLM Agent 技能-记忆架构的启示
开发语言·人工智能·架构·挂谷猜想
城管不管9 小时前
ReAct、Plan-and-Execute、Reflection 三大智能 Agent 范式核心区别
java·人工智能·算法·spring·ai·动态规划
IT小白杨10 小时前
从环境制备到自动化工作流:多账号运营的工程化架构拆解
java·经验分享·自动化·安全架构·指纹浏览器
豆瓣鸡10 小时前
算法日记 - Day3
java·开发语言·算法
萧瑟余晖10 小时前
Java深入解析篇九之NIO详解
java·网络·nio