互联网技术15——ReentrantLock之重入锁、读写锁、非公平锁

synchronized关键字可以实现线程之间的同步互斥给工作,Lock对象锁是一种完成同步互斥工作更优秀的机制,在1.6之后,对synchronized进行了优化,虽然效率上有所提升,但是在灵活度上仍然不如Lock对象。比如嗅探锁定,夺路分支等功能。

重入锁:

在需要同步的代码部分添加锁定,但是最后一定不要忘记了释放锁,否则会造成锁无法释放,其他线程不能执行。

package com.company.lockTest;

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

/**
 * Created by BaiTianShi on 2018/8/23.
 */
public class ReentrantLockTest {

    private Lock lock = new ReentrantLock();
    private  void  method1(){
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName()+"在method1中开始运行");
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"在method1中结束运行");
            Thread.sleep(2000);

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

    private  void  method2(){
        ;
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName()+"在method2中开始运行");
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"在method2中结束运行");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }


    public static  void main(String[] args) {
        ReentrantLockTest r = new ReentrantLockTest();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                r.method1();
            }
        }, "t1");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                r.method2();
            }
        }, "t2");
        t1.start();
        t2.start();

    }
}

执行结果:

t1在method1中开始运行
t1在method1中结束运行
t2在method2中开始运行
t2在method2中结束运行

condition

在使用synchronized的时候,如果需要多线程间进行协调工作,则需要Object的wait()和notify()、notifyAll()方法配合使用。在使用Lcok对象锁的时候,可以使用一个新的等待通知类,他就是condition。这个Condition一定是针对某把锁的,也就是说只有在锁的基础上才能使用condition。

package com.company.lockTest;

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

/**
 * Created by BaiTianShi on 2018/8/23.
 */
public class ReentrantLockTest {

    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    private  void  method1(){
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName()+"在method1中开始运行");
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"在method1将执行等待方法");
            condition.await();
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"在method1跳出等待,继续执行");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    private  void  method2(){
        ;
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName()+"在method2中开始运行");
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"在method2中结束运行并通知等待线程");
            condition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }


    public static  void main(String[] args) {
        ReentrantLockTest r = new ReentrantLockTest();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                r.method1();
            }
        }, "t1");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                r.method2();
            }
        }, "t2");
        t1.start();
        t2.start();

    }
}

运行结果:

t1在method1中开始运行
t1在method1将执行等待方法
t2在method2中开始运行
t2在method2中结束运行并通知等待线程
t1在method1跳出等待,继续执行

 

一个lock创建多condition。

一个Lock可以创建多个condition进行多线程间的交互,非常的灵活,可以使得部分需要唤醒的线程唤醒,其他线程继续等待通知。

package com.company.lockTest;

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

/**
 * Created by BaiTianShi on 2018/8/23.
 */
public class ReentrantLockTest {

    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private  void  method1(){
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName()+"在method1中开始运行");
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"在method1将执行condition1的等待方法");
            condition1.await();
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"在method1跳出condition1的等待,继续执行");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    private  void  method2(){
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName()+"在method2中开始运行");
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"在method2将执行condition1的等待方法");
            condition1.await();
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"在method2跳出condition1的等待,继续执行");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    private  void  method3(){
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName()+"在method3中开始运行");
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"在method3将执行condition2的等待方法");
            condition2.await();
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"在method3跳出condition2的等待,继续执行");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    private  void  method4(){
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName()+"在method4中开始运行");
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"在method4通知因condition1等待的线程");
            condition1.signalAll();

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

    private  void  method5(){
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName()+"在method5中开始运行");
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"在method5通知因condition2等待的线程");
            condition2.signal();

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

    public static  void main(String[] args) {
        ReentrantLockTest r = new ReentrantLockTest();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                r.method1();
            }
        }, "t1");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                r.method2();
            }
        }, "t2");
        Thread t3= new Thread(new Runnable() {
            @Override
            public void run() {
                r.method3();
            }
        }, "t3");
        Thread t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                r.method4();
            }
        }, "t4");
        Thread t5 = new Thread(new Runnable() {
            @Override
            public void run() {
                r.method5();
            }
        }, "t5");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();

    }
}

执行结果

t2在method2中开始运行
t2在method2将执行condition1的等待方法
t3在method3中开始运行
t3在method3将执行condition2的等待方法
t1在method1中开始运行
t1在method1将执行condition1的等待方法
t4在method4中开始运行
t4在method4通知因condition1等待的线程
t5在method5中开始运行
t5在method5通知因condition2等待的线程
t2在method2跳出condition1的等待,继续执行
t1在method1跳出condition1的等待,继续执行
t3在method3跳出condition2的等待,继续执行

读写锁:

读写锁ReentrantReadWriteLock,其核心就是实现读写分离的锁,在高并发的情况下,尤其是读多写少时,性能要远高于ReentrantLock。不同于synchronized和ReentrantLock,同一时间,只能有一个线程访问被锁的代码。读写锁其本质是分成两个锁,即读锁和写锁。在读锁下,多个线程可以并发访问,在写的时候,只能一个一个顺序访问。遵循口诀:读读共享、写写互斥、读写互斥。

package com.company.lockTest;


import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Created by BaiTianShi on 2018/8/23.
 */
public class ReentrantLockTest {

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
    private ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
    private  void  read(){
        try {
            readLock.lock();
            System.out.println(Thread.currentThread().getName()+"读操作开始");
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"读操作结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            readLock.unlock();
        }
    }

    private  void  write(){
        try {
            writeLock.lock();
            System.out.println(Thread.currentThread().getName()+"写操作开始");
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"写操作结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            writeLock.unlock();
        }
    }




    public static  void main(String[] args) {
        ReentrantLockTest r = new ReentrantLockTest();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                r.read();
            }
        }, "t1");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                r.write();
            }
        }, "t2");
        Thread t3= new Thread(new Runnable() {
            @Override
            public void run() {
                r.read();
            }
        }, "t3");
        Thread t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                r.write();
            }
        }, "t4");

        t1.start();
        t2.start();
        t3.start();
        t4.start();

    }
}

运行结果:

t3读操作开始
t1读操作开始
t3读操作结束
t1读操作结束
t2写操作开始
t2写操作结束
t4写操作开始
t4写操作结束
扫描二维码关注公众号,回复: 3002157 查看本文章

针对ReentrantLock方法的补充:

1. getHoldCount() 查询当前线程保持此锁的次数,也就是执行此线程执行lock方法的次数

2.getQueueLength()返回正等待获取此锁的线程估计数,比如启动10个线程,1个线程获得锁,此时返回的是9

3.getWaitQueueLength(Condition condition)返回等待与此锁相关的给定条件的线程估计数。比如10个线程,用同一个condition对象,并且此时这10个线程都执行了condition对象的await方法,那么此时执行此方法返回10

4.hasWaiters(Condition condition)查询是否有线程等待与此锁有关的给定条件(condition),对于指定contidion对象,有多少线程执行了condition.await方法

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

6.hasQueuedThreads()是否有线程等待此锁

7.isFair()该锁是否公平锁

8.isHeldByCurrentThread() 当前线程是否保持锁锁定,线程的执行lock方法的前后分别是false和true

9.isLock()此锁是否有任意线程占用

10.lockInterruptibly()如果当前线程未被中断,获取锁

11.tryLock()尝试获得锁,仅在调用时锁未被线程占用,获得锁

12.tryLock(long timeout TimeUnit unit)如果锁在给定等待时间内没有被另一个线程保持,则获取该锁

要说明的是:

  • tryLock能获得锁就返回true,不能就立即返回false,tryLock(long timeout,TimeUnit unit),可以增加时间限制,如果超过该时间段还没获得锁,返回false
  • lock能获得锁就返回true,不能的话一直等待获得锁
  • lock和lockInterruptibly,如果两个线程分别执行这两个方法,但此时中断这两个线程,前者不会抛出异常,而后者会抛出异常

猜你喜欢

转载自blog.csdn.net/qq_28240551/article/details/81990306