欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java~多线程ReentrantLock类常用的十四个方法, 使用Condition实现多线程的顺序执行

程序员文章站 2022-05-03 20:57:38
...

方法getHoldCount()

  • 该方法的作用是查询当前被这个锁锁定的线程个数, 也就是这个锁执行lock的次数
public class Demo1 {

    public static void main(String[] args) {
        ReentrantLock reentrantLock = new ReentrantLock();
        Thread thread = new Thread() {
            @Override
            public void run() {
                method1();
            }

            public void method1() {
                reentrantLock.lock();
                System.out.println(Thread.currentThread().getName() + " " +
                        reentrantLock.getHoldCount());
                method2();
                reentrantLock.unlock();
            }

            public void method2() {
                reentrantLock.lock();
                System.out.println(Thread.currentThread().getName() + " " +
                        reentrantLock.getHoldCount());
                reentrantLock.unlock();
            }
        };
        thread.start();
    }
}

Java~多线程ReentrantLock类常用的十四个方法, 使用Condition实现多线程的顺序执行

方法getQueueLength()

  • 该方法返回的是想要获取这个锁的线程个数
  • 比如有5个线程,1个线程首先执行await()方法,那么在调用getQueueLength()方法后返回值是4,说明有4个线程同时在等待lock 的释放。
public class Demo2 {

    public static void main(String[] args) throws InterruptedException {
        ReentrantLock reentrantLock = new ReentrantLock();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                reentrantLock.lock();
                try {
                    Thread.sleep(Integer.MAX_VALUE);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    reentrantLock.unlock();
                }
            }
        };
        Thread[] threads = new Thread[5];
        for (int i = 0; i < 5; i++) {
            threads[i] = new Thread(runnable);
        }
        for (int i = 0; i < 5; i++) {
            threads[i].start();
        }
        Thread.sleep(100);
        System.out.println(reentrantLock.getQueueLength());
    }
}

Java~多线程ReentrantLock类常用的十四个方法, 使用Condition实现多线程的顺序执行

方法getWaitQueueLength()

  • 方法int getWaitfQueueI engh(Condition condition)的作用是返回等待与此锁定相关的给定条件Condition的线程估计数,比如有5个线程,每个线程都执行了同一个condition对象的await()方法,则调用getWaitQueueLengh(Condition condition)方法时返回的int值是5。
  • 也就是同一个condition执行await的次数, 也就是目前有多少个线程处于某一个condition的await下
public class Demo3 {

    public static void main(String[] args) {
        ReentrantLock reentrantLock = new ReentrantLock();
        Condition condition = reentrantLock.newCondition();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                reentrantLock.lock();
                try {
                    System.out.println(reentrantLock.getWaitQueueLength(condition));
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        Thread[] threads = new Thread[5];
        for (int i = 0; i < 5; i++) {
            threads[i] = new Thread(runnable);
        }
        for (int i = 0; i < 5; i++) {
            threads[i].start();
        }

    }
}

Java~多线程ReentrantLock类常用的十四个方法, 使用Condition实现多线程的顺序执行

方法hasQueuedThread()和方法hasQueuedThreads()

  • 方法boolean hasQueuedThread(Thread thread) 的作用是查询指定的线程是否正在等待获取此锁定。 也就是查看指定线程想要获取锁.
  • 方法boolean hasQueuedThreads()的作用是查询是否有线程正在等待获取此锁定。也就是这个不指定了, 而是只要有想要这把锁的就返回true
public class Demo4 {

    public static void main(String[] args) throws InterruptedException {
        ReentrantLock reentrantLock = new ReentrantLock();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                reentrantLock.lock();
                try {
                    Thread.sleep(Integer.MAX_VALUE);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    reentrantLock.unlock();
                }
            }
        };
        Thread a = new Thread(runnable);
        a.start();
        Thread.sleep(100);
        Thread b = new Thread(runnable);
        b.start();
        Thread.sleep(100);
        System.out.println("a需要吗? " + reentrantLock.hasQueuedThread(a));
        System.out.println("b需要吗? " + reentrantLock.hasQueuedThread(b));
        System.out.println("有需要吗? " + reentrantLock.hasQueuedThreads());
    }
}

Java~多线程ReentrantLock类常用的十四个方法, 使用Condition实现多线程的顺序执行

方法hasWaiters()

  • 方法boolean hasWaiters(Condition condition)的作用是查询是否有线程正在等待与此锁定有关的condition条件。
  • 也就是在这个condition下有没有线程执行了await还没有唤醒
  • 这个方法必须在加锁的情况下使用不然没有对象监视器的所有权, 从而抛出IllegalMonitorStateException
public class Demo5 {

    public static void main(String[] args) throws InterruptedException {
        ReentrantLock reentrantLock = new ReentrantLock();
        Condition condition = reentrantLock.newCondition();
        Thread thread = new Thread() {
            @Override
            public void run() {
                reentrantLock.lock();
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    reentrantLock.unlock();
                }
            }
        };

        thread.start();
        Thread.sleep(100);
        //注意使用这个方法必须在lock下使用, 不然会没有这个对象监视器的所有权而抛出异常
        reentrantLock.lock();
        System.out.println("有没有等待signal的线程 " + reentrantLock.hasWaiters(condition));
        reentrantLock.unlock();
    }
}

Java~多线程ReentrantLock类常用的十四个方法, 使用Condition实现多线程的顺序执行

方法isFair()

  • 方法boolean isFair()的作用是判断是不是公平锁。 这个很简单 就不做演示了

方法isHeldByCurrentThread()

  • 方法boolean isHeldByCurrentThread()的作用是查询当前线程是否保持此锁定。
  • 也就是这个线程是否执行了lock
public class Demo6 {

    public static void main(String[] args) {
        ReentrantLock reentrantLock = new ReentrantLock();
        System.out.println(reentrantLock.isHeldByCurrentThread());
        reentrantLock.lock();
        System.out.println(reentrantLock.isHeldByCurrentThread());
        reentrantLock.unlock();
    }
}

Java~多线程ReentrantLock类常用的十四个方法, 使用Condition实现多线程的顺序执行

方法isLocked()

  • 方法boolean isLocked()的作用是查询此锁定是否由任意线程保持。
  • 也就是这把锁是否已经执行了lock
public class Demo7 {

    public static void main(String[] args) throws InterruptedException {
        ReentrantLock reentrantLock = new ReentrantLock();
        System.out.println(reentrantLock.isLocked());

        Thread thread = new Thread() {
            @Override
            public void run() {
                reentrantLock.lock();
                System.out.println("执行lock");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    System.out.println("释放lock");
                    reentrantLock.unlock();
                }
            }
        };
        thread.start();
        for (int i = 0; i < 10; i++) {
            System.out.println(reentrantLock.isLocked());
            Thread.sleep(200);
        }


    }
}

Java~多线程ReentrantLock类常用的十四个方法, 使用Condition实现多线程的顺序执行

方法lockInterruptibly()、tryLock()和tryLock(long timeout,TimeUnit unit)

  • 这三个方法大同小异
  • 方法void locklnterruptibly()的作用是:如果当前线程未被中断,则获取锁定,如果已经被中断则出现异常。 也就是我们在普通使用lock方法加锁时, 如果这个线程被中断了是不会抛出异常的, 而使用locklnterruptibly方法加锁如果这个线程中断了是会抛出异常的
  • 方法boolean tryLock()的作用是,仅在调用时锁定未被另一个线程保持的情况下,才获取该锁定。 本意就是我尝试去获取锁, 如果没人拿我就拿, 如果有人拿我就不要这把锁了
  • 方法boolean tryLock(long timeout, TimeUnit unit)的作用是,如果锁定在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁定。 也就是我会支持一段时间去尝试那这个把锁, 在这个时间段里, 我没拿到我就不要了
public class Service1 {

    private ReentrantLock reentrantLock = new ReentrantLock();

    public void method() {
        try {
            if (reentrantLock.tryLock(3, TimeUnit.SECONDS)) {
                System.out.println(Thread.currentThread().getName() + " " +
                        "获取锁的时间:" + System.currentTimeMillis());
                Thread.sleep(10000);
            } else {
                System.out.println(Thread.currentThread().getName() + " 没有获得锁");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (reentrantLock.isHeldByCurrentThread()) {
                reentrantLock.unlock();
            }
        }
    }
}
public class Demo1 {

    public static void main(String[] args) throws InterruptedException {
        Service1 service1 = new Service1();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " 执行method时间" +
                        System.currentTimeMillis());
                service1.method();
            }
        };
        Thread a = new Thread(runnable, "A");
        a.start();
        Thread b = new Thread(runnable, "B");
        b.start();
    }
}

Java~多线程ReentrantLock类常用的十四个方法, 使用Condition实现多线程的顺序执行

方法awaitUninterruptibly()

  • 我没在普通使用await的时候, 如果这个线程中断了, 就会抛出异常, 但是使用awaitUninterruptibly()即使在等待中的线程被打断了, 也不会抛出异常

方法await(time) 和 awaitUntil()

  • 这俩个方法和synchronized的wait(long)和相似, 就是wait等待一段时间, 可以提前唤醒, 也可以等时间到了自动唤醒.
public class Demo2 {

    public static void main(String[] args) throws InterruptedException {
        ReentrantLock reentrantLock = new ReentrantLock();
        Condition condition = reentrantLock.newCondition();

        reentrantLock.lock();
        System.out.println(Thread.currentThread().getName() + " 开始时间:" +
                System.currentTimeMillis());
        condition.await(3, TimeUnit.SECONDS);
        System.out.println(Thread.currentThread().getName() + " 结束时间:" +
                System.currentTimeMillis());
        reentrantLock.unlock();


    }
}

Java~多线程ReentrantLock类常用的十四个方法, 使用Condition实现多线程的顺序执行

使用Condition实现多线程的顺序执行

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created with IntelliJ IDEA.
 * Description: If you don't work hard, you will a loser.
 * User: Listen-Y.
 * Date: 2020-10-10
 * Time: 18:25
 */
public class Run {

    private static ReentrantLock reentrantLock = new ReentrantLock();
    //关键变量
    volatile private static int key = 1;
    //三个condition保证三种线程 挨个运行
    private static Condition conditionA = reentrantLock.newCondition();
    private static Condition conditionB = reentrantLock.newCondition();
    private static Condition conditionC = reentrantLock.newCondition();

    public static void main(String[] args) {
        //实现三个runnable任务
        Runnable runnableA = new Runnable() {
            @Override
            public void run() {
                try {
                    reentrantLock.lock();
                    while (key != 1) {
                        conditionA.await();
                    }
                    for (int i = 0; i < 3; i++) {
                        System.out.println(Thread.currentThread().getName() + " " + i);
                    }
                    key = 2;
                    //唤醒所有B线程
                    conditionB.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    reentrantLock.unlock();
                }
            }
        };
        Runnable runnableB = new Runnable() {
            @Override
            public void run() {
                try {
                    reentrantLock.lock();
                    while (key != 2) {
                        conditionB.await();
                    }
                    for (int i = 0; i < 3; i++) {
                        System.out.println(Thread.currentThread().getName() + " " + i);
                    }
                    key = 3;
                    //唤醒所有C线程
                    conditionC.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    reentrantLock.unlock();
                }
            }
        };
        Runnable runnableC = new Runnable() {
            @Override
            public void run() {
                try {
                    reentrantLock.lock();
                    while (key != 3) {
                        conditionC.await();
                    }
                    for (int i = 0; i < 3; i++) {
                        System.out.println(Thread.currentThread().getName() + " " + i);
                    }
                    key = 1;
                    //唤醒所有A线程
                    conditionA.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    reentrantLock.unlock();
                }
            }
        };

        //创建多个线程
        Thread[] threadsA = new Thread[5];
        Thread[] threadsB = new Thread[5];
        Thread[] threadsC = new Thread[5];
        for (int i = 0; i < 5; i++) {
            threadsA[i] = new Thread(runnableA, "ThreadA");
            threadsB[i] = new Thread(runnableB, "ThreadB");
            threadsC[i] = new Thread(runnableC, "ThreadC");
        }
        //启动所有线程
        for (int i = 0; i < 5; i++) {
            threadsA[i].start();
            threadsB[i].start();
            threadsC[i].start();
        }
    }
}

Java~多线程ReentrantLock类常用的十四个方法, 使用Condition实现多线程的顺序执行