JUC:Lock与ReadWriteLock锁

在这里插入图片描述

synchronized的优缺点

优点:

1:发生异常自动释放锁

2:书写简单

缺点:

1:无法使等待中的线程中断等待

2:无法得知线程是否成功为资源加锁了

3:无法使读操作并发进行

由此引入了Lock与ReadWriteLock接口

Lock

1:加锁的错误写法

public class Test01 {

    public static void main(String[] args) {
        Test01 test01 = new Test01();
        new Thread(() -> {
            test01.test();
        }, "one").start();

        new Thread(() -> {
            test01.test();
        },"tow").start();
    }

    public void test(){
        Lock lock = new ReentrantLock();
        lock.lock();
        try {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName()+" "+i);
                Thread.sleep(10);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }

    }
}

运行结果
在这里插入图片描述
为什么不能同步了呢,原因是Lock的声明写在了业务方法test()里了,当两个线程运行到test()方法时,声明了两个不同的锁,这样的情况下,两个线程使用不同的锁对同一个对象加锁,是可以成功的,所以就无法同步了

将Lock对象的声明写到外面,使多线程使用的锁是同一把,它们就无法对同一个对象进行加锁了(synchronized默认使用同一把锁,这也是synchronized的优点,不用自己编程更多的代码)

2:lock()的正确写法

public class Test02 {
    Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        Test02 test02 = new Test02();
        new Thread(() -> {
            test02.test();
        }, "one").start();

        new Thread(() -> {
            test02.test();
        },"tow").start();
    }

    public void test(){

        lock.lock();
        try {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName()+" "+i);
                Thread.sleep(10);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }

    }
}

3:tryLock()

public class Test03 {
    Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        Test03 test03 = new Test03();
        new Thread(() -> {
            try {
                test03.test();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"one").start();
        new Thread(() -> {
            try {
                test03.test();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"tow").start();
    }

    public void test() throws InterruptedException {
        if(lock.tryLock()){
            try {
                System.out.println(Thread.currentThread().getName()+"获得了锁");
                Thread.sleep(10);
            } finally {
                lock.unlock();
                System.out.println(Thread.currentThread().getName()+"释放了锁");
            }
        }
        else {
            System.out.println(Thread.currentThread().getName()+"加锁失败");
        }
    }
}

运行结果
在这里插入图片描述
4:lockInterruptibly():可中断锁

public class Test04 {
    private Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        Test04 test04 = new Test04();
        Thread thread01 = new Thread(() -> {
                try {
                    test04.test();
                } catch (InterruptedException e) {
                    System.out.println(Thread.currentThread().getName()+" 被中断");
                }
            },"one");

        Thread thread02 = new Thread(() -> {
            try {
                test04.test();
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName()+" 被中断");
            }
        },"tow");

        thread01.start();
        thread02.start();

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        thread02.interrupt();


    }

    public void test() throws InterruptedException {
        lock.lockInterruptibly();
        try {
            System.out.println(Thread.currentThread().getName()+" 获得了锁");
            Thread.sleep(1000);
        }finally {
            lock.unlock();
            System.out.println(Thread.currentThread().getName()+" 释放了锁");
        }

    }
}

运行结果
在这里插入图片描述

ReadWriteLock

ReadWriteLock的简单使用
在这里插入图片描述
ReadWriteLock里面只有两个方法,readLock()与writeLock(),其主要的实现类也只有一个:ReentrantReadWriteLock

1:readLock():读锁

(1)先看普通的锁进行读操作时

public class Test05 {
    Lock lock = new ReentrantLock();
    public static void main(String[] args) {
        Test05 test05 = new Test05();

        new Thread(() -> {
            test05.test();
        },"one").start();

        new Thread(() -> {
            test05.test();
        },"tow").start();
    }

    public void test(){
        lock.lock();
        try {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName()+" 正在进行读操作");
                Thread.sleep(10);
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
            System.out.println(Thread.currentThread().getName()+" 读操作完毕");
        }
    }
}

运行结果
在这里插入图片描述
线程按一个一个执行

(2)再看ReadWriteLock的读锁完成读操作

public class Test06 {
    ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    public static void main(String[] args) {
        Test06 Test06 = new Test06();

        new Thread(() -> {
            Test06.test();
        },"one").start();

        new Thread(() -> {
            Test06.test();
        },"tow").start();
    }

    public void test(){
        readWriteLock.readLock().lock();
        try {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName()+" 正在进行读操作");
                Thread.sleep(10);
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            readWriteLock.readLock().unlock();
            System.out.println(Thread.currentThread().getName()+" 读操作完毕");
        }
    }
}

运行结果
在这里插入图片描述
多个线程可以同时进行读操作,提高了读操作的效率,这就是读写锁的优越性

需要注意的是

  1. 一个资源被加了读锁之后,其他线程可以再对其加读锁,但不能加写锁
  2. 一个资源被加了写锁之后,其他线程不可以再对其加任何锁

synchronized与Lock区别及几个主要锁的概念

见开头的思维导图

————————————
Java并发编程:Lock

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值