您的位置:首页 > 编程语言

高并发编程之ReentrantLock工具类讲解

2019-02-23 21:28 141 查看

一、ReentrantLock介绍
①、ReentrantLock实现了Lock接口,加锁和解锁都需要显式写出,注意一定要在适当时候unlock。
②、可重入锁。可重入锁是指同一个线程可以多次获取同一把锁。也是在实际编程中使用频率很高的一个锁,支持重入性,表示能够对共享资源能够重复加锁,即当前线程获取该锁再次获取不会被阻塞
③、可中断锁。可中断锁是指线程尝试获取锁的过程中,是否可以响应中断。synchronized是不可中断锁,而ReentrantLock则提供了中断功能。
④、公平锁与非公平锁。公平锁是指多个线程同时尝试获取同一把锁时,获取锁的顺序按照线程达到的顺序,而非公平锁则允许线程“插队”。synchronized是非公平锁,而ReentrantLock的默认实现是非公平锁,但是也可以设置为公平锁。

注意:使用重入锁进行加锁是一种显式操作,通过何时加锁与释放锁使重入锁对逻辑控制的灵活性远远大于synchronized关键字。同时,需要注意,有加锁就必须有释放锁,而且加锁与释放锁的分数要相同

二、ReentrantLock相对于synchronized的优势
①、ReentrantLock的优势在于它更灵活、更强大,除了常规的lock()、unlock()之外,还有lockInterruptibly()、tryLock()方法,支持中断、超时。
②、ReentrantLock默认使用非公平锁是基于性能考虑,公平锁为了保证线程规规矩矩地排队,需要增加阻塞和唤醒的时间开销。如果直接插队获取非公平锁,跳过了对队列的处理,速度会更快。
③、可以添加多个检控条件, 如果使用synchronized,则只能使用一个. 使用 reentrant locks 可以有多个wait()/notify() 队列. [译注:直接多new 几个ReentrantLock就可以了,不同的场景/条件用不同的ReentrantLock ]。
④、可以控制线程得到锁的顺序,也就是有公平锁(按照进入顺序得到资源),也可以不按照顺就像.synchronized 一样。
⑤、可以查看锁的状态, 锁是否被锁上了。
⑥可以查看当前有多少线程再等待锁。

三、Java代码示例
①、lock()方法:获取锁,如果锁不可用,出于线程调度目的,将禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态。

package chapter3.locks;

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

/**
* @author czd
*/
public class ReentrantLockTest {
/**
* 非公平锁,当ReentrantLock(true)时是公平锁,都不是绝对公平,只是相对公平
*/
private static final ReentrantLock lock = new ReentrantLock();

public static void main(String[] args) {
for(int i = 0; i < 2; i++){
new Thread(){
@Override
public void run() {
needLock();
}
}.start();
}
}

public static void needLock(){
try {
//不可被中断
lock.lock();
System.out.println(Thread.currentThread().getName()+">>>needLock()方法的效果与needLockLikeSyn()一样,但是速率比它快一点!");
TimeUnit.SECONDS.sleep(2);
System.out.println("任务结束!");
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}

/**
* 这个方法实现的是利用synchronized关键字加锁
*/
public static void needLockLikeSyn(){
synchronized (ReentrantLockTest.class){
try {
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+">>>这个方法的效果与needLock()一样,但是速率比它慢一点!");
}catch (Exception e){
e.printStackTrace();
}
}
}
}

输出结果

②、lockInterruptibly()方法:支持对锁获取的中断。

package chapter3.locks;

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

/**
* @author czd
*/
public class ReentrantLockTest {
/**
* 非公平锁,当ReentrantLock(true)时是公平锁,都不是绝对公平,只是相对公平
*/

private static final ReentrantLock lock = new ReentrantLock();

public static void main(String[] args) {
for(int i = 0; i < 2; i++){
new Thread(){
@Override
public void run() {
needLockInterruptibly();
}
}.start();
}
}

public static void needLockInterruptibly(){
try {
//当抢不到锁时,该线程允许被打断
lock.lockInterruptibly();
System.out.println(Thread.currentThread().getName()+">>>needLockInterruptibly()方法的效果与needLockLikeSyn()一样,但是速率比它快一点!");
TimeUnit.SECONDS.sleep(2);
System.out.println("任务结束!");
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}

/**
* 这个方法实现的是利用synchronized关键字加锁
*/
public static void needLockLikeSyn(){
synchronized (ReentrantLockTest.class){
try {
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+">>>这个方法的效果与needLock()一样,但是速率比它慢一点!");
}catch (Exception e){
e.printStackTrace();
}
}
}
}

输出结果

③、tryLock()方法:如果锁可用,则获取锁,并立即返回值 true。如果锁不可用,则此方法将立即返回值 false。

package chapter3.locks;

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

/**
* @author czd
*/
public class ReentrantLockTest {
/**
* 非公平锁,当ReentrantLock(true)时是公平锁,都不是绝对公平,只是相对公平
*/

private static final ReentrantLock lock = new ReentrantLock();

public static void main(String[] args) {
for(int i = 0; i < 2; i++){
new Thread(){
@Override
public void run() {
needTryLock();
}
}.start();
}
}

public static void needTryLock(){
if (lock.tryLock()){
try {
System.out.println(Thread.currentThread().getName()+">>>needTryLock()方法的效果与needLockLikeSyn()一样,但是速率比它快一点!");
TimeUnit.SECONDS.sleep(2);
System.out.println("任务结束!");
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}else{
System.out.println(Thread.currentThread().getName() + ">>>没有获得锁!");
}
}

/**
* 这个方法实现的是利用synchronized关键字加锁
*/
public static void needLockLikeSyn(){
synchronized (ReentrantLockTest.class){
try {
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+">>>这个方法的效果与needLock()一样,但是速率比它慢一点!");
}catch (Exception e){
e.prin
4000
tStackTrace();
}
}
}
}

输出结果

④、tryLock(long time,TimeUnit unit)方法:如果锁在给定的等待时间内空闲,并且当前线程未被 中断,则获取锁。

package chapter3.locks;

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

/**
* @author czd
*/
public class ReentrantLockTest {
/**
* 非公平锁,当ReentrantLock(true)时是公平锁,都不是绝对公平,只是相对公平
*/

private static final ReentrantLock lock = new ReentrantLock();

public static void main(String[] args) {
for(int i = 0; i < 2; i++){
new Thread(){
@Override
public void run() {
try {
needTryLock(2);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}.start();
}
}

public static void needTryLock(long seconds) throws InterruptedException{
if (lock.tryLock(seconds,TimeUnit.SECONDS)){
try {
System.out.println(Thread.currentThread().getName()+">>>needTryLock()方法的效果与needLockLikeSyn()一样,但是速率比它快一点!");
TimeUnit.SECONDS.sleep(5);
System.out.println("任务结束!");
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}else{
System.out.println(Thread.currentThread().getName() + ">>>在"+seconds+"秒内没有获得锁!");
}
}

/**
* 这个方法实现的是利用synchronized关键字加锁
*/
public static void needLockLikeSyn(){
synchronized (ReentrantLockTest.class){
try {
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+">>>这个方法的效果与needLock()一样,但是速率比它慢一点!");
}catch (Exception e){
e.printStackTrace();
}
}
}
}

输出结果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: