博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
多线程--线程同步锁Lock锁
阅读量:2049 次
发布时间:2019-04-28

本文共 4275 字,大约阅读时间需要 14 分钟。

多线程–线程同步锁–Lock锁-ReentrantLock

之前说了线程同步机制Synchronize锁,其实除此之外还有一种JUC的Lock锁也能实现线程同步。而且Lock实现类ReentrantLock相比Synchronize有更大的灵活性,更加丰富,更是适合大多场景的使用。

先来简单的对比下ReentrantLock和Synchronize吧。

  1. Synchronsize锁是独占锁,加锁和释放锁都是自动的,只要加上关键字synchronize或者代码块就行。使用起来很简单,但是呢灵活性较差。ReentrantLock也是独占锁,但是它需要手动的加锁(lock等)和释放锁(unlock),使用的起来相对复杂了点,但是灵活性好,且ReentrantLock提供了丰富的方法。
  2. Synchronsize和ReentrantLock都是可重入锁(可以多次使用锁:举个例子,方法A使用了锁,其实调用B,但是B也使用了锁,这是调用B的时候不用重新获取锁)。但是都是需要释放锁才能让其它线程拿到锁。
  3. Synchronize一旦拿不到锁,产生了死锁等待状态时,相应不能中断,而ReentrantLock提供了相应中单的锁。
  4. 最主要的就是ReentrantLock还可以实现公平锁机制。什么叫公平锁呢?也就是在锁上等待时间最长的线程将获得锁的使用权。通俗的理解就是谁排队时间最长谁先执行获取锁。

与Synchronize不同的是,ReentrantLock提供了多个锁,可以根据不同需求处理线程同步问题。下面我们重点介绍下ReentrantLock锁,Synchronize的介绍请查看之前的博客。

ReentrantLock是JUC包下的类(java.util.concurrent.locks.ReentrantLock),实现了Lock接口。

在这里插入图片描述
ReentrantLock的释放锁都是一样unlock方法,下面主要看下ReentrantLock不同的锁。
不实现线程同步的时候,不加锁效果:

public class ReenTrantLockThread {    public static void main(String[] args) {        ThreadTest threadTest = new ThreadTest();        new Thread(threadTest,"小明").start();        new Thread(threadTest,"小王").start();    }}class ThreadTest implements Runnable{    final Lock lock = new ReentrantLock();    @Override    public void run() {        study();    }    public void study(){        for (int i = 0; i < 10; i++) {            System.out.println(Thread.currentThread().getName()+":我正在学习");        }    }}

结果:

在这里插入图片描述
小明和小王疯由cpu调度学习。加了锁之后,让一个人学习完再下一个线程拿锁学习(注意哦,下一个线程不一定是另一个人哦,由cpu调度)

(1)Lock() 这个锁就是普通也是常用的锁,和Synchronize锁差不多,一旦拿到锁之后必须等待释放锁,才能继续拿锁,否则会出现线程死锁,所以使用结束之后一定要释放锁。

注意:为了防止不释放锁,一般将加锁内容放到try里面,然后在finally里面释放锁,这样保证一定会释放锁。

public void study(){        lock.lock();        try {    /            for (int i = 0; i < 5; i++) {                System.out.println(Thread.currentThread().getName()+":我正在学习");            }        }catch (Exception e){        }finally {            lock.unlock()        }    }

结果: 让一个人学习完再下一个线程拿锁学习!!!

在这里插入图片描述

(2) tryLock()锁,我叫它尝试锁,它是用来尝试获取锁,如果能获取到那么可以占有锁使用,如果拿不到我们也可以处理其他事物。它是有返回值的,类型boolean,如果拿到了锁就返回true,拿不到就返回false,所以不管怎么的它都会立马返回一个值。

public void study(){        boolean flag = lock.tryLock();        if(flag){            try {                for (int i = 0; i < 5; i++) {                    System.out.println(Thread.currentThread().getName()+":我正在学习");                }            }catch (Exception e){            }finally {                lock.unlock();            }        }else {            System.out.println(Thread.currentThread().getName()+":我没拿到锁,那我去看电视了");        }    }

结果:

在这里插入图片描述
(3)tryLock(long timeout, TimeUnit unit),用法跟tryLock是一样的,不同的是可以指定等待时间,就是锁我拿锁,如果指定时间后还没拿到锁我就返回false,时间没到那我就继续等待锁释放。

public void study() throws InterruptedException {        boolean flag = lock.tryLock(5000,TimeUnit.MILLISECONDS); // 等待5秒钟拿不到锁就返回false        if(flag){            try {                for (int i = 0; i < 5; i++) {                    System.out.println(Thread.currentThread().getName()+":我正在学习");                }            }catch (Exception e){            }finally {                lock.unlock();            }        }else {            System.out.println(Thread.currentThread().getName()+":我没拿到锁,那我去看电视了");        }    }

结果:5秒内成功拿到锁。

在这里插入图片描述
我们给线程加上一个sleep,让线程休息总时间超过5秒,
在这里插入图片描述
(4)lockInterruptibly()中断锁,使用这个锁可有主动主断线程使用Thread.interrupt()。前提是这个线程用到锁了,在没有用锁的情况下是用不了的。这个不好演示,用法如下:
在这里插入图片描述
然后说说ReentrantLock特殊的锁机制,公平锁和非公平锁。
就跟字面上意思差不多,
公平锁意思就是哪个线程排队时间长就让谁优点调度。
非公平锁意思就是不管线程啥时候开始排的队,我就让cpu看心情调度。
使用方法非常简单,只需要在初始化锁的时候加上,true(公平)或者false(不公平)参数。默认就是false
公平锁:

final Lock lock = new ReentrantLock(true);public void study() throws InterruptedException {        for (int i = 0; i <2 ; i++) {            try {                lock.lock(); // 等待5秒钟拿不到锁就返回false                System.out.println(Thread.currentThread().getName()+":我正在学习");                //Thread.sleep(2000);            }catch (Exception e){            }finally {                lock.unlock();            }        }    }

结果:大家不要挤,人人有份。

在这里插入图片描述
非公平锁:

final Lock lock = new ReentrantLock(false);    public void study() throws InterruptedException {        for (int i = 0; i <2 ; i++) {            try {                lock.lock(); // 等待5秒钟拿不到锁就返回false                System.out.println(Thread.currentThread().getName()+":我正在学习");                //Thread.sleep(2000);            }catch (Exception e){            }finally {                lock.unlock();            }        }    }

结果:

在这里插入图片描述下片介绍:读写锁。

转载地址:http://njhof.baihongyu.com/

你可能感兴趣的文章
剑指offer 8-11.斐波那契数列 跳台阶 变态跳台阶 矩形覆盖
查看>>
剑指offer 12.二进制中1的个数
查看>>
剑指offer 13.数值的整数次方
查看>>
剑指offer 14.调整数组顺序使奇数位于偶数前面
查看>>
剑指offer 15.链表中倒数第k个节点
查看>>
剑指offer 16.反转链表
查看>>
剑指offer 17.合并两个排好序的链表
查看>>
剑指offer 18.树的子结构
查看>>
剑指offer 19.二叉树的镜像
查看>>
剑指offer 20.顺时针打印矩阵
查看>>
剑指offer 21.包含min函数的栈
查看>>
剑指offer 23.从上往下打印二叉树
查看>>
剑指offer 25.二叉树中和为某一值的路径
查看>>
剑指offer 26. 数组中出现次数超过一半的数字
查看>>
剑指offer 27.二叉树的深度
查看>>
剑指offer 29.字符串的排列
查看>>
剑指offer 31.最小的k个树
查看>>
剑指offer 32.整数中1出现的次数
查看>>
剑指offer 33.第一个只出现一次的字符
查看>>
剑指offer 34.把数组排成最小的数
查看>>