多线程05--Lock

上一篇:多线程04--线程的原子性、CAS_fengxianaa的博客-CSDN博客

1. 基础概念

/**
 * Lock:是一个接口,jdk1.5后的另一种加锁方式
 *
 *  有了 synchronized,那为什么还需要Lock?
 *      1. 使用 synchronized,如果其中代码执行的速度特别慢,其他线程便只能干巴巴地等待,非常影响程序执行效率。
 *         而 Lock 可以做到只等待一定的时间,如果还获取不到锁,就去做其他事情。
 *
 *      2. 使用 synchronized,当多个线程执行读操作时,依然会阻塞,但其实,读和读之间是不冲突的
 *         而 Lock 可以做到多个读线程之间不阻塞
 *
 *  ReentrantLock:可重入锁,是 Lock 的代表实现类
 */
public class Lock01_ReentrantLock01 {

    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        new Thread(() ->{
            lock.lock();//加锁
            try {
                System.out.println(Thread.currentThread().getName() + "加锁后执行。。。。。。");
                ThreadHelper.sleep(3000);
            } finally {
                //释放锁,为了保证Lock锁一定会释放,所以要在finally中加上这句代码
                lock.unlock();
            }
        }).start();

        ThreadHelper.sleep(3000);

        new Thread(() ->{
            lock.lock();//加锁
            System.out.println(Thread.currentThread().getName() + "加锁后执行。。。。。。");
            lock.unlock();//释放锁,为了保证Lock锁一定会释放,所以要在finally中加上这句代码
        }).start();

    }
}

2. 基础方法

/**
 * ReentrantLock 常用方法
 *      lock()
 *          阻塞当前线程,直到获取锁,阻塞时,调用interrupt没用
 *
 *      lockInterruptibly()
 *          判断线程是否已中断
 *              是:报 InterruptedException
 *              否:阻塞当前线程,直到获取锁,阻塞时,如果调用interrupt,报 InterruptedException
 *
 *      unlock()
 *          释放锁
 *
 */
public class Lock01_ReentrantLock02 {

    public static void main(String[] args) throws InterruptedException {
        Lock lock = new ReentrantLock();
        new Thread(() ->{
            lock.lock();//加锁
            System.out.println(Thread.currentThread().getName() + "加锁后执行。。。。。。");
            ThreadHelper.sleep(3000);
            lock.unlock();//释放锁,为了保证Lock锁一定会释放,所以要在finally中加上这句代码
        }).start();

        ThreadHelper.sleep(500);

        Thread t = new Thread(() ->{
            lock.lock();//加锁
//                lock.lockInterruptibly();//中断时,抛出 InterruptedException
            System.out.println(Thread.currentThread().getName() + "加锁后执行。。。。。。");
            lock.unlock();
        });
        t.start();

        ThreadHelper.sleep(100);
        t.interrupt();
    }
}

常用方法:

/**
 * ReentrantLock 常用方法
 *      tryLock()
 *          尝试获取锁,该方法不阻塞线程
 *              成功:true
 *              失败:false
 *
 *      tryLock(long timeout, TimeUnit unit)
 *          在指定时间内阻塞线程,直到获取锁,阻塞时,如果调用interrupt,报 InterruptedException
 *              成功:true
 *              失败:false
 *
 */
public class Lock01_ReentrantLock03 {

    public static void main(String[] args) throws InterruptedException {
        Lock lock = new ReentrantLock();
        new Thread(() ->{
            lock.lock();//加锁
            System.out.println(Thread.currentThread().getName() + "加锁后执行。。。。。。");
            ThreadHelper.sleep(3000);
            lock.unlock();//释放锁,为了保证Lock锁一定会释放,所以要在finally中加上这句代码
        }).start();

        ThreadHelper.sleep(500);

        Thread t = new Thread(() ->{
            boolean bool = lock.tryLock();//尝试获取锁
//            boolean bool = lock.tryLock(5, TimeUnit.SECONDS);
            if(bool){
                System.out.println(Thread.currentThread().getName() + "加锁后执行。。。。。。");
                lock.unlock();
            }else{
                System.out.println(Thread.currentThread().getName() + "没有拿到锁。。。。。。");
            }
        });
        t.start();

        ThreadHelper.sleep(100);
        t.interrupt();
    }
}

Condition

/**
 * Condition:配合Lock,唤醒指定的线程
 *
 *      await()
 *          当前线程等待被唤醒,等待时候释放锁,如果等待时被interrupt,抛出 InterruptedException
 *
 *      signal()
 *          唤醒调用 await() 方法的线程,当前线程释放锁后,调用 await() 方法的线程会继续执行
 *          如果有好几个线程都调用了 await(),那么唤醒等待时间最长的
 *
 *      signalAll()
 *         当前线程释放锁后,唤醒所有调用 await() 方法的线程
 */
public class Lock01_ReentrantLock04 {

    public static void main(String[] args) throws InterruptedException {
        Lock lock = new ReentrantLock();
        Condition one = lock.newCondition();

        new Thread(() -> {
            try {
                lock.lock();
                System.out.println(Thread.currentThread().getName() + "加锁后等待。。。。。。");
                one.await();//线程等待,等待时候释放锁,当调用one.signal()之后,继续往下执行
                System.out.println(Thread.currentThread().getName() + "苏醒,继续执行。。。。。。。。。。。。");
            } catch (Exception e) {
            } finally {
                lock.unlock();
            }
        },"线程A").start();

        ThreadHelper.sleep(3000);

        new Thread(() -> {
            try {
                lock.lock();
                System.out.println(Thread.currentThread().getName() + "加锁后等待。。。。。。");
                one.await();//线程等待,等待时候释放锁,当调用one.signal()之后,继续往下执行
                System.out.println(Thread.currentThread().getName() + "苏醒,继续执行。。。。。。。。。。。。");
            } catch (Exception e) {
            } finally {
                lock.unlock();
            }
        },"线程B").start();

        ThreadHelper.sleep(5000);

        new Thread(() -> {
            try {
                lock.lock();
                System.out.println(Thread.currentThread().getName() + "执行one.signal()。。。。。。");
//                one.signal();//这时候线程A、B,都在等待,当线程C释放锁后,等待时间最长的继续运行
                one.signalAll();
                ThreadHelper.sleep(3000);
            } catch (Exception e) {
            } finally {
                lock.unlock();
            }
        },"线程C").start();


    }
}

3. 公平锁和非公平锁

/**
 * 公平锁和非公平锁
 *     公平锁:    讲究先来后到。比如,同时有多个线程在等待一个锁,当锁被释放时,等待时间最久的线程(最先请求的线程)会获得锁,现实场景:排队买票
 *     非公平锁:   谁抢到就是谁的,可能导致某个线程一直抢不到锁
 *
 * synchronized 的本质就是非公屏锁
 */
public class Lock01_ReentrantLock05 {

    public static void main(String[] args) {
        Lock lock = new ReentrantLock();//默认非公屏锁
        lock = new ReentrantLock(true);//公平锁
    }
}

4. ReadWriteLock

/**
 * ReadWriteLock    读写锁,也是一个接口
 *
 * ReentrantReadWriteLock 可重入的读写锁,是ReadWriteLock的主要实现类
 *      允许多个读线程同时访问,但不允许写和读、写和写同时访问。
 *      相对于 ReentrantLock (排他锁),提高了并发性
 *
 */
public class Lock02_ReadWriteLock01 {

    public static void main(String[] args) throws InterruptedException {
        ReadWriteLock lock = new ReentrantReadWriteLock();
        /**
         * 1. 多个线程竞争读锁,不会产生阻塞
         */
        for(int i=0;i<2;i++){
            new Thread(() -> {
                lock.readLock().lock();//使用读锁
                System.out.println(Thread.currentThread().getName()+"拿到了读锁。。。。。。");
                ThreadHelper.sleep(3000);
                lock.readLock().unlock();// 实际中,这句代码需要放到 finally 中
            }).start();
        }

        /**
         * 2. 多个线程竞争写锁,会产生阻塞
         */
//        for(int i=0;i<2;i++){
//            new Thread(() -> {
//                lock.writeLock().lock();
//                System.out.println(Thread.currentThread().getName()+"拿到了写锁。。。。。。");
//                ThreadHelper.sleep(3000);
//                lock.writeLock().unlock();// 实际中,这句代码需要放到 finally 中
//            }).start();
//        }

        /**
         * 3. 锁降级:写锁——>读锁,即 同一个线程先获取写锁,还没释放,仍然可以继续获取读锁
         */
//        lock.writeLock().lock();
//        System.out.println("主线程获取了写锁。。。。。。");
//        lock.readLock().lock();
//        System.out.println("主线程又获取了读锁。。。。。。");
//        lock.readLock().unlock();
//        lock.writeLock().unlock();
    }
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值