Multi-threaded programming (eight) - Lock and lock Detailed category ReentrantLock

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/swadian2008/article/details/100145405

table of Contents

A, ReentrantLock synchronize

Second, use implement waiting Condition / notification - to select notification

Third, fair and unfair lock lock

Fourth, waiting and waiting for the automatic wake-interruptible

1, condition.awaitUniterruptibly () waits for interruptible

2, condition.awaitUnitil (time) wait for the automatic wake-up

Fifth, write a write lock mutex lock ReentrantReadWriteLock--

Six, ReentranLock class common API

1, counting the number of threads

2, the thread state is determined

3, the lock state is determined

4, to obtain the lock mode


In addition to the synchronized keyword mutual exclusion between threads can be achieved, ReentrantLock can also synchronize effects, and the synchronized keyword in the expansion of more powerful features than.

ReentrantLock use under what circumstances?

When the need to implement three unique features of ReentrantLock (interruptible wait, to achieve fair locks, condition notification)

Achieve different:

synchronized keyword synchronization by JVM implementation

Lock Classes be achieved codes JDK

A, ReentrantLock synchronize

Use: Call ReentranLock object's Lock () method to get the lock, call the unlock () method to release the lock.

Test code:

Creating MyService class

public class MyService {

    private Lock lock = new ReentrantLock();

    public void methodA(){
        try {
            lock.lock();
            System.out.println("线程:"+Thread.currentThread().getName()+"——A方法执行开始...");
            Thread.sleep(3000);
            System.out.println("线程:"+Thread.currentThread().getName()+"——A方法执行结束...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            // 不管执行是否异常,都要释放锁
            lock.unlock();
        }
    }

    public void methodB(){
        try {
            lock.lock();
            System.out.println("线程:"+Thread.currentThread().getName()+"——B方法执行开始...");
            Thread.sleep(3000);
            System.out.println("线程:"+Thread.currentThread().getName()+"——B方法执行结束...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            // 不管执行是否异常,都要释放锁
            lock.unlock();
        }
    }
}

Create threads --A: execution method A, lock contention

public class ThreadA extends Thread {

    private MyService myService;

    public ThreadA(MyService myService){
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.methodA();
    }
}

Create threads --B: execution method B, lock contention

public class ThreadB extends Thread {

    private MyService myService;

    public ThreadB(MyService myService){
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.methodB();
    }
}

Create threads --C: execution method C, lock contention

public class ThreadC extends Thread {

    private MyService myService;

    public ThreadC(MyService myService){
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.methodA();
    }
}

Create execution class:

public class ExecuteMethod {
    public static void main(String[] args) {
        MyService myService = new MyService();
        ThreadA a = new ThreadA(myService);
        a.setName("a");
        ThreadB b = new ThreadB(myService);
        b.setName("b");
        ThreadC c = new ThreadC(myService);
        c.setName("c");
        a.start();
        b.start();
        c.start();
    }
}

Results of the:

Second, use implement waiting Condition / notification - to select notification

Condition objects compared to the synchronized keyword to wait for notification mechanism has better flexibility, there can thread notifies selective.

Use: thread waits condition.await (); thread notifies condition.signal () / condition.signalAll ()

Test code:

Creating MyService class

public class MyService {

    private Lock lock = new ReentrantLock();

    // 条件一
    private Condition conditionA = lock.newCondition();

    // 条件二
    private Condition conditionB = lock.newCondition();

    public void awaitA(){
        try {
            lock.lock();
            System.out.println("线程:"+Thread.currentThread().getName()+"——A方法await()开始...");
            conditionA.await();// 线程等待,使用条件一
            System.out.println("线程:"+Thread.currentThread().getName()+"——A方法await()结束...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            // 不管执行是否异常,都要释放锁
            lock.unlock();
        }
    }

    public void awaitB(){
        try {
            lock.lock();
            System.out.println("线程:"+Thread.currentThread().getName()+"——B方法await()开始...");
            conditionB.await();// 线程等待,使用条件二
            System.out.println("线程:"+Thread.currentThread().getName()+"——B方法await()结束...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            // 不管执行是否异常,都要释放锁
            lock.unlock();
        }
    }

    public void signalAll_A(){
        try {
            lock.lock();
            System.out.println("线程:"+Thread.currentThread().getName()+"——methodAll_A方法signal()开始...");
            conditionA.signalAll();
            System.out.println("线程:"+Thread.currentThread().getName()+"——methodAll_A方法signal()结束...");
        } finally {
            // 不管执行是否异常,都要释放锁
            lock.unlock();
        }
    }

    public void signalAll_B(){
        try {
            lock.lock();
            System.out.println("线程:"+Thread.currentThread().getName()+"——methodAll_B方法signal()开始...");
            conditionB.signalAll();
            System.out.println("线程:"+Thread.currentThread().getName()+"——methodAll_B方法signal()结束...");
        } finally {
            // 不管执行是否异常,都要释放锁
            lock.unlock();
        }
    }
}

Create a thread A: execution method A, the thread waits

public class ThreadA extends Thread {

    private MyService myService;

    public ThreadA(MyService myService){
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.awaitA();
    }
}

Create threads B: execution method B, the thread waits

public class ThreadB extends Thread {

    private MyService myService;

    public ThreadB(MyService myService){
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.awaitB();
    }
}

Creating the implementation class: Wait making, wake-up call method

public class ExecuteMethod {
    public static void main(String[] args) throws InterruptedException {
        MyService myService = new MyService();
        ThreadA a = new ThreadA(myService);
        a.setName("a");
        ThreadB b = new ThreadB(myService);
        b.setName("b");
        a.start();
        b.start();
        Thread.sleep(3000);
        myService.signalAll_A();// 选择性唤醒线程,置唤醒A
    }
}

Test Results:

The previous output, showing the selective use of condition notice object can implement thread.

Third, fair and unfair lock lock

Lock lock lock into equity and non-equity locks, fair lock is in order, first in first out (FIFO), non-equity lock-free order.

Below demonstrates the implementation of ReentranLock class of equity and non-equity locked lock

Test code:

Creating MyService class

public class MyService {

    private Lock lock;

    public MyService(boolean isFair){
        super();
        lock = new ReentrantLock(isFair);
    }

    public void method(){
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName()+"- 被锁定");
        } finally {
            lock.unlock();
        }
    }
}

Creating execution method - this time to create a fair lock

public class ExecuteMethod {
    public static void main(String[] args) throws InterruptedException {
        // 设置为true 表示此锁为公平锁
        MyService myService = new MyService(true);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                myService.method();
            }
        };
        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();
        }
    }
}

Results of the:

Then modify the code, modify the non-fair locks

public class ExecuteMethod {
    public static void main(String[] args) throws InterruptedException {
        // 设置为false 表示此锁为非公平锁
        MyService myService = new MyService(false);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                myService.method();
            }
        };
        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();
        }
    }
}

Results of the:

Fourth, waiting and waiting for the automatic wake-interruptible

1, condition.awaitUniterruptibly ()  waits for interruptible

condition.await ()  thread while waiting for the interruption thrown

condition.awaitUniterruptibly ()  thread while waiting for the interrupt will not throw an exception

Test code:

First look at condition.await () waits for throw an exception case

public class MyService {

    private ReentrantLock lock = new ReentrantLock();

    private Condition condition = lock.newCondition();

    public void testMethod(){
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName()+"等待开始...");
            condition.await();// await()中断会抛出异常
            System.out.println(Thread.currentThread().getName()+"等待结束...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    static class ExcuteThread extends Thread{
        private MyService myService;

        public ExcuteThread(MyService myService){
            super();
            this.myService = myService;
        }

        public void run(){
            myService.testMethod();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyService myService = new MyService();
        ExcuteThread ex = new ExcuteThread(myService);
        ex.start();
        Thread.sleep(3000);
        ex.interrupt();//中断线程
    }
}

Results of the:

Next, the method waits replaced condition.awaitUniterruptibly (), test again

public void testMethod(){
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName()+"等待开始...");
            condition.awaitUninterruptibly();// 更换方法中的等待方式
            System.out.println(Thread.currentThread().getName()+"等待结束...");
        }finally {
            lock.unlock();
        }
    }

Results of the:

2, condition.awaitUnitil (Time)  wait for the automatic wake-up

condition.awaitUnitil(time) 线程在一定时间后自动唤醒自己,在这个时间到达前也可以被其他线程唤醒

测试代码:

public class MyService {

    private ReentrantLock lock = new ReentrantLock();

    private Condition condition = lock.newCondition();

    public void testMethod(){
        try {
            lock.lock();
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.SECOND,2);
            System.out.println(Thread.currentThread().getName()+"等待开始...");
            condition.awaitUntil(calendar.getTime());// 2s后将自动唤醒
            System.out.println(Thread.currentThread().getName()+"等待结束,自动唤醒...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
        lock.unlock();
        }
    }

    static class ExcuteThread extends Thread{
        private MyService myService;

        public ExcuteThread(MyService myService){
            super();
            this.myService = myService;
        }

        public void run(){
            myService.testMethod();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyService myService = new MyService();
        ExcuteThread ex = new ExcuteThread(myService);
        ex.start();
    }
}

五、读写锁ReentrantReadWriteLock——写锁互斥

ReentrantReadWriteLock读写锁可以使在不需要操作实例变量的方法中(比如写数据),使代码能够异步执行,提高运行效率。

读写锁的互斥逻辑:只要程序运行中有写的逻辑,执行就是互斥的,只读程序不会进行同步。

测试代码:

创建MyService类

public class MyService {

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public void readOnly(){
        try {
            lock.readLock().lock();// 使用只读锁
            System.out.println(Thread.currentThread().getName()+":获取只读锁...");
            Thread.sleep(3000);
            System.out.println(Thread.currentThread().getName()+":执行只读方法结束...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.readLock().unlock();
        }
    }

    public void writeOnly(){
        try {
            try {
                lock.writeLock().lock();// 使用只写锁
                System.out.println(Thread.currentThread().getName()+":获取只写锁...");
                Thread.sleep(3000);
                System.out.println(Thread.currentThread().getName()+":执行只写方法结束...");
            } finally {
                lock.writeLock().unlock();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

创建线程A:先获取读锁,后获取写锁

public class ThreadA extends Thread {

    private MyService myService;

    public ThreadA(MyService myService){
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.readOnly();
        myService.writeOnly();
    }
}

创建线程B:先获取读锁,后获取写锁

public class ThreadB extends Thread {

    private MyService myService;

    public ThreadB(MyService myService){
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.readOnly();
        myService.writeOnly();
    }
}

创建执行类:验证读为——共享锁,写为——互斥锁

public class ExecuteMethod {
    public static void main(String[] args) throws InterruptedException {
        // 设置为false 表示此锁为非公平锁
        MyService myService = new MyService();
        ThreadA threadA = new ThreadA(myService);
        threadA.setName("A线程");
        ThreadB threadB = new ThreadB(myService);
        threadB.setName("B线程");
        threadA.start();
        threadB.start();
    }
}

执行结果:

六、ReentranLock类常用API

1、统计线程个数

int getHoldCount() 统计锁定线程的个数

int getQueueLength() 获取等待线程的个数

int getWaitQueueLength() 获取condition下执行了await()方法的线程数

2、判断线程状态

boolean hasQueueThread() 查询指定线程是否正在等待锁

boolean hasQueueThreads() 查询是否有线程正在等待锁

boolean hasWaiters(Condition condition) 查询有没有线程执行了此condition的await()方法

3、判断锁状态

boolean isFair() 判断是不是公平锁

boolean isHeldByCurrentThread() 判断线程是否被锁定

boolean isLocked() 判断锁是否被占用

4、获取锁的方式

void lockInterruptibly() 线程中断剖出异常

boolean tryLock() 尝试获取未被占用的锁

boolean tryLock(Long timeout,TimeUnit unit) 锁在一定时间类没有被占用,获取该锁

Guess you like

Origin blog.csdn.net/swadian2008/article/details/100145405