Java多线程(4)

Java多线程(4)

Lock的使用

synchronized是java中的一个关键字,也就是说是Java语言内置的特性。那么为什么会出现Lock呢?

  • Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;

  • Lock和synchronized有一点非常大的不同,采用synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。

Java Lock API中的一些重要接口和类是:

  • 锁(Lock):这是Lock API的基本接口。它提供了 synchronized 关键字的所有功能,以及为锁定创建不同条件的其他方法,为线程等待锁定提供超时功能。一些重要的方法是 lock() 获取锁,unlock() 释放锁,tryLock() 等待锁定一段时间,newCondition() 创建条件等。

  • 条件(Condition):条件对象类似于对象等待通知( Object wait-notify)模型,具有创建不同等待集的附加功能。Condition 对象始终由 Lock 对象创建。一些重要的方法是 await(),类似于Object.wait() 和 signal(),signalAll(),类似于 Object.notify() 和 Object.notifyAll() 方法。

  • 读写锁(ReadWriteLock):它包含一对关联的锁,一个用于只读操作,另一个用于写入。只要没有写入线程,读锁可以由多个读取线程同时保持。写锁是独占的。

  • 重入锁(ReentrantLock):这是最广泛使用的 Lock 接口实现类。此类以与 synchronized 关键字类似的方式实现 Lock 接口。除了 Lock 接口实现之外,ReentrantLock 还包含一些实用程序方法来获取持有锁的线程,等待获取锁线程等。

ReentrantLock

构造函数:


ReentrantLock()
创建一个 ReentrantLock的实例


ReentrantLock(boolean fair)
根据给定的公平政策创建一个 ReentrantLock的实例

方法:


getHoldCount()
查询当前线程对此锁的暂停数量。


getOwner()
返回当前拥有此锁的线程,如果不拥有,则返回 null 。


getQueuedThreads()
返回包含可能正在等待获取此锁的线程的集合。


getQueueLength()
返回等待获取此锁的线程数的估计。


getWaitingThreads(Condition condition)
返回包含可能在与此锁相关联的给定条件下等待的线程的集合。


getWaitQueueLength(Condition condition)
返回与此锁相关联的给定条件等待的线程数的估计。


hasQueuedThread(Thread thread)
查询给定线程是否等待获取此锁。


hasQueuedThreads()
查询是否有线程正在等待获取此锁。


hasWaiters(Condition condition)
查询任何线程是否等待与此锁相关联的给定条件。


isFair()
如果此锁的公平设置为true,则返回 true 。


isHeldByCurrentThread()
查询此锁是否由当前线程持有。


isLocked()
查询此锁是否由任何线程持有。


lock()
获得锁。


lockInterruptibly()
获取锁定,除非当前线程是 interrupted 


newCondition()
返回Condition用于这种用途实例Lock实例

toString()
返回一个标识此锁的字符串以及其锁定状态


tryLock()
只有在调用时它不被另一个线程占用才能获取锁


tryLock(long timeout, TimeUnit unit)
如果在给定的等待时间内没有被另一个线程 占用 ,并且当前线程尚未被 保留,则获取该锁( interrupted) 


unlock()
尝试释放此锁。

ReentrantLock是一个可重入且独占式的锁,它具有与使用synchronized监视器锁相同的基本行为和语义,但与synchronized关键字相比,它更灵活、更强大,增加了轮询、超时、中断等高级功能。

扫描二维码关注公众号,回复: 8761885 查看本文章

ReentrantLock,顾名思义,它是支持可重入锁的锁,是一种递归无阻塞的同步机制。除此之外,该锁还支持获取锁时的公平和非公平选择

先上个例子:

看看如何实现同步操作:


public class MyService {

    private Lock lock = new ReentrantLock();

    public void testMethod(){

//        获取锁
        lock.lock();
        for (int i = 0; i < 5; i++) {
            System.out.println("Thread name  "+Thread.currentThread().getName()
            +" ( "+ (i+1));
        }
        System.out.println("");

//        释放锁
        lock.unlock();
    }
}

public class MyThread extends Thread{

    private MyService myService;

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

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



public class Run {

    public static void main(String[] args) {

        MyService myService = new MyService();

        MyThread myThread1 = new MyThread(myService);
        MyThread myThread2 = new MyThread(myService);
        MyThread myThread3 = new MyThread(myService);
        MyThread myThread4 = new MyThread(myService);
        MyThread myThread5 = new MyThread(myService);

        myThread1.start();
        myThread2.start();
        myThread3.start();
        myThread4.start();
        myThread5.start();

    }
}

class MyService_1 {
    private ReentrantLock lock = new ReentrantLock();

    public void methodA() {
        lock.lock();
        try {
            System.out.println("MethodA begin ThreadName=" + Thread.currentThread().getName());
            for (int i = 1; i <= 3; i++) {
                System.out.println("ThreadName=" + Thread.currentThread().getName() + "  " + i);
                Thread.sleep(1000);
            }
            System.out.println("MethodA end ThreadName=" + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void methodB() {
        lock.lock();
        try {
            System.out.println("MethodB begin ThreadName=" + Thread.currentThread().getName());
            for (int i = 1; i <= 3; i++) {
                System.out.println("ThreadName=" + Thread.currentThread().getName() + "  " + i);
                Thread.sleep(1000);
            }
            System.out.println("MethodB end ThreadName=" + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

class ThreadA extends Thread {

    private MyService_1 service;

    ThreadA(MyService_1 service) {
        this.service = service;
    }

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

class ThreadB extends Thread {

    private MyService_1 service;

    ThreadB(MyService_1 service) {
        this.service = service;
    }

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

public class T1 {


//    多线程执行不同代码块互斥

    
    public static void main(String[] args) {
        MyService_1 service = new MyService_1();
        ThreadA threadA = new ThreadA(service);
        threadA.setName("A");

        ThreadB threadB = new ThreadB(service);
        threadB.setName("B");
        threadA.start();
        threadB.start();
    }
}

Condition接口的使用

在Java程序中,任意一个Java对象,都拥有一组监视器方法(定义在java.lang.Object类上),主要包括wait()、wait(long)、notify()、notifyAll()方法,这些方法与synchronized关键字配合,可以实现等待/通知模式。

Condition接口也提供了类似Object的监视器方法,与Lock配合可以实现等待/通知模式

Condition接口中的方法:


await()
导致当前线程等到发信号或 interrupted 


await(long time, TimeUnit unit)
使当前线程等待直到发出信号或中断,或指定的等待时间过去


awaitNanos(long nanosTimeout)
使当前线程等待直到发出信号或中断,或指定的等待时间过去


awaitUninterruptibly()
使当前线程等待直到发出信号


awaitUntil(Date deadline)
使当前线程等待直到发出信号或中断,或者指定的最后期限过去


signal()
唤醒一个等待线程


signalAll()
唤醒所有等待线程

使用notify()和notifyAll()方法进行通知时,被通知的线程是由JVM随机选择的,但使用ReentrantLock结合Condition是可以实现“选择性通知”的

简单的实现等待通知机制:

public class MyService {

    private Lock lock = new ReentrantLock();

    public Condition condition = lock.newCondition();

    public void await(){
        try {
            lock.lock();
            System.out.println("等待时间为  "+System.currentTimeMillis());
            condition.await();
        } catch (InterruptedException e){
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void signal(){
        try {
            lock.lock();
            System.out.println("通知时间为  "+System.currentTimeMillis());
            condition.signal();
        } finally {
            lock.unlock();
        }
    }
}

public class ThreadA extends Thread{

    private MyService myService;

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

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



public class Run {

    public static void main(String[] args) throws InterruptedException {

        MyService myService = new MyService();

        ThreadA a = new ThreadA(myService);

        a.start();

        Thread.sleep(5000);

        myService.signal();

    }


//    Object类中的wait()方法相当于Condition类中的await()方法。
//Object类中的wait(long timeout)方法相当于Condition类中的await(long time,TimeUnit unit)方法。
//Object类中的notify()方法相当于Condition类中的signal()方法。
//Object类中的notifyAll()方法相当于Condition类中的signalAll()方法。

}

累计加数(多个线程进行操作,需要保证线程数据安全)

public class T1 {

    private static final int N = 3;
    private int count = 0;
    private int finishCount = 0;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void doSomething() {
        for (int i=0; i<1000; i++) {
            synchronized (this) {
                count ++;
            }
        }
        lock.lock();
        finishCount ++;
        if (finishCount == N) {
            condition.signal();
        }
        lock.unlock();
    }

    public static void main(String[] args) {
        T1 test = new T1();
        for (int i=0; i<N; i++) {
            Runnable runnable = () -> test.doSomething();
            new Thread(runnable).start();
        }

        test.lock.lock();
        try {
            test.condition.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            test.lock.unlock();
        }

        System.out.println(test.count);
    }
}


实现生产者消费者模式:一对一交替打印

public class MyService {

    private ReentrantLock lock = new ReentrantLock();

    private Condition condition = lock.newCondition();

    private boolean hasVal = false;

    public void set(){
        try {
            lock.lock();
            while (hasVal == true){
                condition.await();
            }
            System.out.println("打印*");
            hasVal=true;
            condition.signal();
        } catch (InterruptedException e){
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }


    public void get(){
        try {
            lock.lock();
            while (hasVal==false){
                condition.await();
            }
            System.out.println("打印+");
            hasVal = false;
            condition.signal();
        } catch (InterruptedException e){
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

public class Thread_1 extends Thread{

    private MyService myService;

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

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            myService.set();
        }
    }
}

public class Thread_2 extends Thread{

    private MyService myService;

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

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            myService.get();
        }
    }
}



public class Run {

    public static void main(String[] args) {

        MyService myService = new MyService();

        Thread_1 thread_1 = new Thread_1(myService);

        thread_1.start();

        Thread_2 thread_2 = new Thread_2(myService);

        thread_2.start();


    }
}

实现生产者消费者模式:多对多交替打印


public class MyService {

    private ReentrantLock lock = new ReentrantLock();

    private Condition condition = lock.newCondition();

    private boolean hasVal = false;

    public void set(){
        try {
            lock.lock();
            while (hasVal == true){
                System.out.println("可能**连续");
                condition.await();
            }
            System.out.println("打印*");
            hasVal=true;
//            condition.signal();  可能会造成假死现象

            condition.signalAll();
        } catch (InterruptedException e){
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void get(){
        try {
            lock.lock();
            while (hasVal==false){
                System.out.println("可能++连续");
                condition.await();
            }
            System.out.println("打印+");
            hasVal = false;
            //            condition.signal();  可能会造成假死现象

            condition.signalAll();
        } catch (InterruptedException e){
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }


}

public class Thread_1 extends Thread{

    private MyService myService;

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

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            myService.set();
        }
    }
}


public class Thread_2 extends Thread{

    private MyService myService;

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

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            myService.get();
        }
    }
}

public class Run {

    public static void main(String[] args) {

        MyService myService = new MyService();

        Thread_1[] thread_1s = new Thread_1[10];

        Thread_2[] thread_2s = new Thread_2[10];

        for (int i = 0; i < 10; i++) {
            thread_1s[i] = new Thread_1(myService);
            thread_2s[i] = new Thread_2(myService);
            thread_1s[i].start();
            thread_2s[i].start();

        }

    }
}


出现连续打印的情况是因为:

使用了一个condition对象,再结合signalAll()方法来唤醒所有的线程,那么唤醒的就很有可能是同类,所以出现连续打印的情况

ReentrantLock中的公平锁和非公平锁

ReentrantLock有一个很大的特点,就是可以指定锁是公平锁还是非公平锁

公平锁表示线程获取锁的顺序是按照线程排队的顺序来分配的

非公平锁就是一种获取锁的抢占机制,是随机获得锁的,先来的未必就一定能先得到锁,从这个角度讲,synchronized其实就是一种非公平锁。非公平锁的方式可能造成某些线程一直拿不到锁,自然是非公平的了

new ReentrantLock的时候有一个单一参数的构造函数表示构造的是一个公平锁还是非公平锁,传入true就可以了

例子:


public class T1 {

    private Lock lock = new ReentrantLock(true);

    public void testMethod()
    {
        try
        {
            lock.lock();
            System.out.println("ThreadName" + Thread.currentThread().getName() + "获得锁");
        }
        finally
        {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        final T1 td = new T1();
        Runnable runnable = new Runnable()
        {
            public void run()
            {
                System.out.println("◆线程" + Thread.currentThread().getName() + "运行了");
                td.testMethod();
            }
        };
        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();

    }
}

看到结果里面获得锁的顺序和线程启动顺序是一致的,这就是公平锁

再看看非公平锁:

public class T2 {

    private Lock lock = new ReentrantLock(false);

    public void testMethod()
    {
        try
        {
            lock.lock();
            System.out.println("ThreadName" + Thread.currentThread().getName() + "获得锁");
        }
        finally
        {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        final T2  td = new T2 ();
        Runnable runnable = new Runnable()
        {
            public void run()
            {
                System.out.println("◆线程" + Thread.currentThread().getName() + "运行了");
                td.testMethod();
            }
        };
        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();

    }
}

启动顺序和获得锁的顺序完全乱了

getHoldCount()

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

public class T3 {

    private ReentrantLock lock = new ReentrantLock();

    public void serviceMethod1(){
        try {
            lock.lock();
            System.out.println(" serviceMethod1 getHoldCount  " + lock.getHoldCount());
            serviceMethod2();
        } finally {
            lock.unlock();
        }
    }

    public void serviceMethod2(){
        try {
            lock.lock();
            System.out.println(" serviceMethod2 getHoldCount " +lock.getHoldCount());
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {

        T3 t3 = new T3();
        t3.serviceMethod1();

    }
}


getQueueLength()

方法getQueueLength()的作用是返回正等待获取此锁定的线程估计数


public class T4 {

    public ReentrantLock lock = new ReentrantLock();

    public void m1(){
        try {
            lock.lock();
            System.out.println("name=  " + Thread.currentThread().getName()
            +"  进入方法  ");
            Thread.sleep(6000);
        } catch (InterruptedException e){
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {

        final T4 t4 = new T4();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                t4.m1();
            }
        };

        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(3000);
        System.out.println("线程数量  " + t4.lock.getQueueLength()
        +"在等待获取锁");
    }
}

getWaitQueueLength()

getWaitQueueLength作用是返回等待与此锁定相关的给定条件condition的线程估计数量


public class T5 {

    private ReentrantLock lock  = new ReentrantLock();

    private Condition condition = lock.newCondition();

    public void waitme(){
        try {
            lock.lock();
            condition.await();
        } catch (InterruptedException e){
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }


    public void notifyme(){
        try {
            lock.lock();
            System.out.println(" 有 " + lock.getWaitQueueLength(condition)
            +"  个线程正在等待  ");
            condition.signal();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {

        final T5 t5 = new T5();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                t5.waitme();
            }
        };

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

        t5.notifyme();

    }
}

hasQueuedThread()

方法boolean hasQueuedThread作用是查询指定的线程是否正在等待获取此方法锁定


public class T6 {

    public ReentrantLock lock = new ReentrantLock();

    public Condition condition = lock.newCondition();

    public void waitM(){

        try {
            lock.lock();
            Thread.sleep(6000);
        } catch (InterruptedException e){
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public static void main(String[] args) throws InterruptedException {

        final T6 t6 = new T6();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                t6.waitM();
            }
        };

        Thread thread = new Thread(runnable);
        thread.start();
        Thread.sleep(5000);
        Thread thread1 = new Thread(runnable);
        thread1.start();
        Thread.sleep(5000);
        System.out.println(t6.lock.hasQueuedThread(thread));
        System.out.println(t6.lock.hasQueuedThread(thread1));
        System.out.println(t6.lock.hasQueuedThreads());
    }

}

hasWaiters()

方法boolean hasWaiters作用是查询是否有线程正在等待与此锁定有关的condition条件

public class T7 {

    private ReentrantLock lock = new ReentrantLock();

    private Condition condition = lock.newCondition();

    public void waitM(){
        try {
            lock.lock();
            condition.await();
        } catch (InterruptedException e){
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void notifyM(){
        try {
            lock.lock();
            System.out.println("有没有线程正在等待  "
            + lock.hasWaiters(condition)+
                    "线程数是多少"+
                    lock.getWaitQueueLength(condition));
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {

        final T7 t7= new T7();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                t7.waitM();
            }
        };

        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(3000);
        t7.notifyM();
    }

}


isFair()

方法isFair的作用是判对是不是公平锁

public class T8 {

    private ReentrantLock lock;

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

    public void serM(){
        try {
            lock.lock();
            System.out.println("公平锁情况  " + lock.isFair());
        } finally {
            lock.unlock();
        }
    }


    public static void main(String[] args) {


        final T8 t8 = new T8(true);

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                t8.serM();
            }
        };

        Thread thread = new Thread(runnable);
        thread.start();

        final T8 t81 = new T8(false);

        runnable = new Runnable() {
            @Override
            public void run() {
                t81.serM();
            }
        };

        thread = new Thread(runnable);
        thread.start();
    }
}

isHeldByCurrentThread()

方法isHeldByCurrentThread的作用是查询当前线程是否保持此锁定

public class T9 {

    private ReentrantLock lock;

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

    public void serM(){
        try {
            System.out.println(lock.isHeldByCurrentThread());
            lock.lock();
            System.out.println(lock.isHeldByCurrentThread());
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {

        final T9 t9 = new T9(true);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                t9.serM();
            }
        } ;

        Thread thread = new Thread(runnable);
        thread.start();


    }
}

使用Condition实现顺序执行

public class F {

    volatile public static int nextPrintWho = 1;
}



public class Run {

    volatile private static int nextPrintWho = 1;

    private static ReentrantLock lock = new ReentrantLock();

    final private static Condition CONDITIONA = lock.newCondition();

    final private static Condition CONDITIONB = lock.newCondition();

    final private static Condition CONDITIONC = lock.newCondition();

    public static void main(String[] args) {

        Thread threadA = new Thread(){

            @Override
            public void run() {
                try {
                    lock.lock();
                    while (nextPrintWho!=1){
                        CONDITIONA.await();
                    }
                    for (int i = 0; i < 3; i++) {
                        System.out.println("  TA  " + (i+1));
                    }
                    nextPrintWho = 2;
                    CONDITIONB.signalAll();
                } catch (InterruptedException e){
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };

        Thread threadB = new Thread(){


            @Override
            public void run() {
                try {
                    lock.lock();
                    while (nextPrintWho!=2){
                        CONDITIONB.await();
                    }
                    for (int i = 0; i < 3; i++) {
                        System.out.println("   TB   " + (i+1));
                    }
                    nextPrintWho = 3;
                    CONDITIONC.signalAll();
                } catch (InterruptedException e){
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };


        Thread threadC = new Thread(){


            @Override
            public void run() {
                try {
                    lock.lock();
                    while (nextPrintWho!=3){
                        CONDITIONB.await();
                    }
                    for (int i = 0; i < 3; i++) {
                        System.out.println("  TC   " + (i+1));
                    }
                    nextPrintWho = 1;
                    CONDITIONC.signalAll();
                } catch (InterruptedException e){
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };


        Thread[] a1 = new Thread[5];
        Thread[] a2 = new Thread[5];
        Thread[] a3 = new Thread[5];

        for (int i = 0; i < 5; i++) {
            a1[i] = new Thread(threadA);
            a2[i] = new Thread(threadB);
            a3[i] = new Thread(threadC);
            a1[i].start();
            a2[i].start();
            a3[i].start();
        }

    }
}


ReentrantReadWriteLock类

ReentrantReadWriteLock是Lock的另一种实现方式,我们已经知道了ReentrantLock是一个排他锁,同一时间只允许一个线程访问,而ReentrantReadWriteLock允许多个读线程同时访问,但不允许写线程和读线程、写线程和写线程同时访问。相对于排他锁,提高了并发性。在实际应用中,大部分情况下对共享数据(如缓存)的访问都是读操作远多于写操作,这时ReentrantReadWriteLock能够提供比排他锁更好的并发性和吞吐量。

读写锁内部维护了两个锁,一个用于读操作,一个用于写操作。所有 ReadWriteLock实现都必须保证 writeLock操作的内存同步效果也要保持与相关 readLock的联系。也就是说,成功获取读锁的线程会看到写入锁之前版本所做的所有更新。

ReentrantReadWriteLock支持以下功能:

  • 支持公平和非公平的获取锁的方式;

  • 支持可重入。读线程在获取了读锁后还可以获取读锁;写线程在获取了写锁之后既可以再次获取写锁又可以获取读锁;

  • 还允许从写入锁降级为读取锁,其实现方式是:先获取写入锁,然后获取读取锁,最后释放写入锁。但是,从读取锁升级到写入锁是不允许的;

  • 读取锁和写入锁都支持锁获取期间的中断;

  • Condition支持。仅写入锁提供了一个 Conditon 实现;读取锁不支持 Conditon ,readLock().newCondition() 会抛出 UnsupportedOperationException。

构造函数:



ReentrantReadWriteLock()
创建一个新的 ReentrantReadWriteLock与默认(非空)订购属性


ReentrantReadWriteLock(boolean fair)
创建一个新的 ReentrantReadWriteLock与给定的公平政策


方法:


getOwner()
返回当前拥有写锁的线程,如果不拥有,则返回 null 

protected Collection<Thread>	getQueuedReaderThreads()
返回一个包含可能正在等待获取读取锁的线程的集合

protected Collection<Thread>	getQueuedThreads()
返回一个包含可能正在等待获取读取或写入锁定的线程的集合

protected Collection<Thread>	getQueuedWriterThreads()
返回一个包含可能正在等待获取写入锁的线程的集合

int	getQueueLength()
返回等待获取读取或写入锁定的线程数的估计

int	getReadHoldCount()
查询当前线程对此锁的可重入读取保留数

int	getReadLockCount()
查询为此锁持有的读取锁的数量

protected Collection<Thread>	getWaitingThreads(Condition condition)
返回包含可能在与写锁相关联的给定条件下等待的线程的集合

int	getWaitQueueLength(Condition condition)
返回与写入锁相关联的给定条件等待的线程数的估计

int	getWriteHoldCount()
查询当前线程对此锁的可重入写入数量

boolean	hasQueuedThread(Thread thread)
查询给定线程是否等待获取读取或写入锁定

boolean	hasQueuedThreads()
查询是否有任何线程正在等待获取读取或写入锁定

boolean	hasWaiters(Condition condition)
查询任何线程是否等待与写锁相关联的给定条件

boolean	isFair()
如果此锁的公平设置为true,则返回 true 

boolean	isWriteLocked()
查询写锁是否由任何线程持有

boolean	isWriteLockedByCurrentThread()
查询写锁是否由当前线程持有

ReentrantReadWriteLock.ReadLock	readLock()
返回用于阅读的锁

String	toString()
返回一个标识此锁的字符串以及其锁定状态

ReentrantReadWriteLock.WriteLock	writeLock()
返回用于写入的锁

先上个例子:

读读共享


public class Service {

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public void read(){

        try {

            try {

                lock.readLock().lock();
                System.out.println(" 获得读锁 " + Thread.currentThread().getName()
                + "   " +System.currentTimeMillis());

                Thread.sleep(10000);
            } finally {
                lock.readLock().unlock();
            }


        } catch (InterruptedException e){
            e.printStackTrace();
        }

    }
}


public class A extends Thread{

    private Service service;

    public A(Service service) {
        this.service = service;
    }

    @Override
    public void run() {
        service.read();
    }
}



public class B extends Thread{

    private Service service;

    public B(Service service) {
        this.service = service;
    }

    @Override
    public void run() {
        service.read();
    }
}


public class Run {

    public static void main(String[] args) {

        Service service = new Service();

        A a = new A(service);

        a.setName("A");

        B b = new B(service);

        b.setName("B");

        a.start();

        b.start();

    }
}



从控制台打印时间可以看出:

两个线程几乎同时进入lock()方法后面的代码

读写互斥的例子:


public class Queue {

    //共享数据,只能有一个线程 写数据,但可以 多个线程读数据
    private Object data = null;
    private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

    public void get() {
        rwl.readLock().lock();//上读锁,其他线程只能读。
        System.out.println(Thread.currentThread().getName() +
                "准备好读取 data!");
        try {
            Thread.sleep((long) (Math.random() * 1000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println(Thread.currentThread().getName() +
                    "已经读到了data  "+data);
            rwl.readLock().unlock();//释放读锁,最好放在finally里面
        }
    }

    public void put(Object data) {
        rwl.writeLock().lock();//加上写锁,不允许其他线程 读写
        System.out.println(Thread.currentThread().getName() +
                "准备好写 data!!");
        try {
            Thread.sleep((long) (Math.random() * 1000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            this.data=data;
            System.out.println(Thread.currentThread().getName() +
                    "已经写好了 data!! "+data);
            rwl.writeLock().unlock();//释放锁
        }
    }

}



public class TestReadWriteLock {

    public static void main(String[] args) {

        final Queue q3 = new Queue();
        for (int i = 0; i < 4; ++i) {
            new Thread() {
                public void run() {
                    while (true) {
                        q3.get();
                    }
                }
            }.start();
        }
        for (int i = 0; i < 4; ++i) {
            new Thread(""+i) {
                public void run() {
                    while (true) {
                        q3.put(new Random().nextInt(10000));
                    }
                }
            }.start();

            System.out.println("");
        }


    }
}

发布了189 篇原创文章 · 获赞 58 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/Coder_py/article/details/104038255