多线程锁的使用(ReentrantLock/Condition/ReentrantReadWriteLock)

在java多线程中,我们可以使用Synchronized关键字来实现线程间的同步互斥工作,那么其中有一个更优秀的机去完成这个”同步互斥”工作,它就是lock对象,我们主要学习两种锁重入锁和读写锁,他们具有比Synchronized更为强大的功能,并且有嗅探锁定、多路分支等功能。

ReentrantLock重入锁

在需要进行同步的代码部分加上锁定,但不要忘记最后一定要释放锁定,不然会造成锁永远无法释放,其他线程永远进不来的情况。

public class UseReentrantLock {

    private ReentrantLock lock = new ReentrantLock();
    public void method1(){
        try {
            lock.lock();
            System.out.println("当前线程:"+Thread.currentThread().getName()+"进入method1...");
            Thread.sleep(1000);
            System.out.println("当前线程:"+Thread.currentThread().getName()+"退出method1...");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            lock.unlock();
        }
    }

    public void method2(){
        try {
            lock.lock();
            System.out.println("当前线程:"+Thread.currentThread().getName()+"进入method2..");
            Thread.sleep(2000);
            System.out.println("当前线程:"+Thread.currentThread().getName()+"退出method2...");
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        final UseReentrantLock ur = new UseReentrantLock();
        Thread t1 = new Thread(new Runnable(){
            @Override
            public void run() {
                ur.method1();
                ur.method2();
            }
        },"t1");
        t1.start();
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
锁与等待通知

在使用Synchronized的时候,如果需要多线程键进行协作工作则需要Object的wait()和notify()/notifyAll()方法配合工作。
那么同样,我们在使用Lock的时候,可以使用一个新的等待/通知的类,Condition。这个Condition一定是针对具体的某一把锁的。也就是只有锁的基础上才会产生Condition。
使用Condition类进行通信

public class UseCondition {

    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void method1(){
        try {
            lock.lock();
            System.out.println("当前线程:"+Thread.currentThread().getName()+"进入等待状态..");
            Thread.sleep(3000);
            System.out.println("当前线程:"+Thread.currentThread().getName()+"释放锁..");
            condition.await();//object wait 会释放锁
            System.out.println("当前线程:"+Thread.currentThread().getName()+"继续执行..");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            lock.unlock();
        }
    }

    public void method2(){
        try {
            lock.lock();
            System.out.println("当前线程:"+Thread.currentThread().getName()+"进入..");
            Thread.sleep(3000);
            System.out.println("当前线程:"+Thread.currentThread().getName()+"发出唤醒..");
            condition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            lock.unlock();
        }
    }

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

}
多Condition

我们可以通过lock对象产生多个Condition进行线程间交互。

public class UseManyCondition {

    private ReentrantLock lock = new ReentrantLock();
    private Condition c1 = lock.newCondition();
    private Condition c2 = lock.newCondition();

    public void m1(){
        try {
            lock.lock();
            System.out.println("当前线程:"+Thread.currentThread().getName()+"进入m1方法等待..");
            c1.await();
            System.out.println("当前线程:"+Thread.currentThread().getName()+"方法m1继续..");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            lock.unlock();
        }
    }

    public void m2(){
        try {
            lock.lock();
            System.out.println("当前线程:"+Thread.currentThread().getName()+"进入m2方法等待..");
            c1.await();
            System.out.println("当前线程:"+Thread.currentThread().getName()+"方法m2继续..");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            lock.unlock();
        }
    }

    public void m3(){
        try {
            lock.lock();
            System.out.println("当前线程:"+Thread.currentThread().getName()+"进入m3方法等待..");
            c2.await();
            System.out.println("当前线程:"+Thread.currentThread().getName()+"方法m3继续..");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            lock.unlock();
        }
    }

    public void m4(){
        try {
            lock.lock();
            System.out.println("当前线程:"+Thread.currentThread().getName()+"唤醒...");
            c1.signalAll();
        } catch(Exception e){
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
    }

    public void m5(){
        try {
            lock.lock();
            System.out.println("当前线程:"+Thread.currentThread().getName()+"唤醒...");
            c2.signalAll();
        } catch(Exception e){
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        final UseManyCondition umc = new UseManyCondition();
        Thread t1 = new Thread(new Runnable(){
            @Override
            public void run() {
                umc.m1();
            }
        },"t1");
        Thread t2 = new Thread(new Runnable(){
            @Override
            public void run() {
                umc.m2();
            }
        },"t2");
        Thread t3 = new Thread(new Runnable(){
            @Override
            public void run() {
                umc.m3();
            }
        },"t3");
        Thread t4 = new Thread(new Runnable(){
            @Override
            public void run() {
                umc.m4();
            }
        },"t4");
        Thread t5 = new Thread(new Runnable(){
            @Override
            public void run() {
                umc.m5();
            }
        },"t5");
        t1.start();
        t2.start();
        t3.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t4.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t5.start();

    }

}
Lock/Condition其他方法和用法

公平锁和非公平锁

Lock lock = new ReentranLock(boolean isNonFair);

公平锁维护顺序,非公平锁没有顺序。
Lock用法:
tryLock():尝试获得锁,获得结果用true/false返回。
isFair()
isLocked()
getHoldCount()
lockInterruptibly()
getQueueLength()
getWaitQueueLength()
hasQueuedThread(Thread thread)
hasQueuedThreads()
hasWaiters()

读写锁ReentrantReadWriteLock

其核心就是实现读写分离的锁。在高并发访问下,尤其是读多写少的情况下,效率明显高于重入锁。之前学Synchronized、ReentrantLock时,我们知道同一时间内,只能有一个线程进行访问被锁定的代码,那么读写锁就不同,其本质就是分成两个锁,即读锁写锁。在读锁下多个线程可以并发的访问,但在写锁的情况下只能一个一个的顺序访问。
口诀:读读共享 写写互斥 读写互斥

public class UseReentrantReadWriteLock {

    private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    //获取读写锁
    private ReadLock readLock = rwLock.readLock();
    private WriteLock writeLock = rwLock.writeLock();

    public void read(){
        try {
            readLock.lock();
            System.out.println("当前线程:"+Thread.currentThread().getName()+"进入...");
            Thread.sleep(3000);
            System.out.println("当前线程:"+Thread.currentThread().getName()+"退出...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            readLock.unlock();
        }
    }

    public void write(){
        try {
            writeLock.lock();
            System.out.println("当前线程:"+Thread.currentThread().getName()+"进入...");
            Thread.sleep(3000);
            System.out.println("当前线程:"+Thread.currentThread().getName()+"退出...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            writeLock.unlock();
        }
    }

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

        //读读共享  
        t1.start();
        t2.start();
        //写写互斥
        t3.start();
        t4.start();
        //读写互斥
        t1.start();
        t3.start();
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值