java多线程---重入锁ReentrantLock

1.定义
重入锁ReentrantLock,支持重入的锁,表示一个线程对资源的重复加锁。
2.底层实现
每个锁关联一个线程持有者和计数器,当计数器为0时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应的方法;成功后,JVM会记下锁的持有线程,并且将计数器置为1;此时其它线程请求该锁,则必须等待;而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增;当线程退出同步代码块时,计数器会递减,如果计数器为0,则释放该锁。
3.使用样例

eg:

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockTest implements Runnable{
    public static int i = 100;
    public static ReentrantLock rl = new ReentrantLock();

    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            rl.lock();
            if(i>0){
                System.out.println(Thread.currentThread().getName() + " : " + i--);
            }
            rl.unlock();
        }
    }

    public static void main(String[] args) {
        ReentrantLockTest rlt = new ReentrantLockTest();
        Thread t1 = new Thread(rlt);
        Thread t2 = new Thread(rlt);
        t1.start();
        t2.start();
    }

}

中断响应

synchronized:线程等待锁,要么获得锁继续执行,要么保持等待。

ReentrantLock:等待锁的过程中,可以根据需求取消对锁的请求。

eg:

import java.util.concurrent.locks.ReentrantLock;

public class IntLock implements Runnable {
    int lock;
    public static ReentrantLock lock1 = new ReentrantLock();
    public static ReentrantLock lock2 = new ReentrantLock();

    public IntLock(int lock){
        this.lock = lock;
    }

    @Override
    public void run() {
        try{
            if(lock == 1){
                try{
                    lock1.lockInterruptibly();      // 如果当前线程未被中断,则获取锁。
                }catch(Exception e){
                    e.printStackTrace();
                }
                lock2.lockInterruptibly();
                System.out.println(Thread.currentThread().getId()+"执行完毕");
            }else{
                lock2.lockInterruptibly();
                try{
                    Thread.sleep(1000);
                }catch(Exception e){

                }
                lock1.lockInterruptibly();
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(lock1.isHeldByCurrentThread()){      //查询当前线程是否保持此锁
                lock1.unlock();
            }
            if(lock2.isHeldByCurrentThread()){      //查询当前线程是否保持此锁
                lock2.unlock();
            }
            System.out.println(Thread.currentThread().getId()+":线程退出");
        }

    }

    public static void main(String[] args) throws InterruptedException {
        IntLock l1 = new IntLock(1);
        IntLock l2 = new IntLock(2);
        Thread t1 = new Thread(l1);
        Thread t2 = new Thread(l2);
        t1.start();
        t2.start();
        Thread.sleep(2000);
        t2.interrupt();         //中断线程,不中断,则产生死锁

    }

}

锁申请等待限时

如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。

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

public class TimeLock implements Runnable {

    public static ReentrantLock rl = new ReentrantLock();

    @Override
    public void run() {
        try {
            if(rl.tryLock(5, TimeUnit.SECONDS)){
                Thread.sleep(6000);
                System.out.println(Thread.currentThread().getId()+"执行完毕");
            }else{
                System.out.println(Thread.currentThread().getId()+"get lock failed");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            if(rl.isHeldByCurrentThread())rl.unlock();
        }
    }

    public static void main(String[] args) {
        TimeLock tl = new TimeLock();
        Thread t1 = new Thread(tl);
        Thread t2 = new Thread(tl);
        t1.start();
        t2.start();
    }

}

公平锁

在ReentrantLock中很明显可以看到其中同步包括两种,分别是公平的FairSync和非公平的NonfairSync。公平锁的作用就是严格按照线程启动的顺序来执行的,不允许其他线程插队执行的;而非公平锁是允许插队的。默认情况下ReentrantLock是通过非公平锁来进行同步的,包括synchronized关键字都是如此,因为这样性能会更好。

public ReentrantLock(boolean fair) //如果此锁应该使用公平的排序策略,则该参数为 true

import java.util.concurrent.locks.ReentrantLock;

public class FairLock implements Runnable{

    public static ReentrantLock rl = new ReentrantLock(true);

    @Override
    public void run() {
        while(true){
            try {
                rl.lock();
                System.out.println(Thread.currentThread().getName()+" : get lock");
            } catch (Exception e) {
            }finally{
                rl.unlock();
            }
        }
    }

    public static void main(String[] args) {
        FairLock fl = new FairLock();
        Thread t1 = new Thread(fl,"Thread_One");
        Thread t2 = new Thread(fl,"Thread_Two");
        t1.start();
        t2.start();
    }

}

在重入锁的实现中,包含3个要素

1.原子状态,使用CAS操作来存储当前锁的状态,判断锁是否被别的线程持有

2.等待队列,所有没有请求到锁的线程,会进入到队列进行等待,待有线程释放锁后,系统能从等待队列唤醒一个线程继续工作。

3.阻塞原语park()和unpark(),用来挂起和恢复线程,没有得到锁的线程会被挂起

原文地址:https://www.cnblogs.com/Ch1nYK/p/9245153.html

时间: 2024-08-10 17:51:12

java多线程---重入锁ReentrantLock的相关文章

JAVA多线程重入锁ReentrantLock应用

package concurrent; import java.util.concurrent.*; import java.util.concurrent.locks.ReentrantLock; /** * @Auther:zhl * @Date:2019/7/13 * @Description: 并发测试,重入锁ReentrantLock解决并发问题 */ public class ConcurrentSample { //并发线程数量 private static int users =

java 可重入锁ReentrantLock的介绍

一个小例子帮助理解 话说从前有一个村子,在这个村子中有一口水井,家家户户都需要到这口井里打水喝.由于井水有限,大家只能依次打水.为了实现家家有水喝,户户有水用的目标,村长绞尽脑汁,最终想出了一个比较合理的方案. 首先,在水井边上安排一个看井人,负责维持秩序. 然后,打水时,以家庭为单位,哪个家庭任何人先到井边,就可以先打水,而且如果一个家庭占到了打水权,其家人这时候过来打水不用排队.而那些没有抢占到打水权的人,一个一个挨着在井边排成一队,先到的排在前面. 最后,打水的人打完水以后就告诉看井人,看

Java 多线程 重入锁

作为关键字synchronized的替代品(或者说是增强版),重入锁是synchronized的功能扩展.在JDK 1.5的早期版本中,重入锁的性能远远好于synchronized,但从JDK 1.6开始,JDK优化了synchronized,使两者性能差距不大.重入锁使用java.util.concurrent.locks.ReentrantLock类来实现. 使用重入锁可以指定何时加锁和何时释放锁,对逻辑控制的灵活性远远好于synchronized,退出临界区时必须释放锁.之所以称为重入锁,

Java并发程序设计(12)并发锁之可重入锁ReentrantLock

1.1. 可重入锁ReentrantLock ReentrantLock是java并发库中提供的可重入锁.与synchronized同步块相比,有相似也有不同.相似的地方有: (1)都可以实现多线程之间的同步,避免对共享资源的访问冲突. (2)都是可重入的,即一个已经获取锁的线程可以再次获得同一个锁,synchronized也类似. 不同的地方有: (1)ReentrantLock更灵活,获取锁和释放锁可以在同一个方法中,也可以在不同方法中.synchronized通常用在同一个方法体内. (2

Java 重入锁 ReentrantLock 原理分析

1.简介 可重入锁ReentrantLock自 JDK 1.5 被引入,功能上与synchronized关键字类似.所谓的可重入是指,线程可对同一把锁进行重复加锁,而不会被阻塞住,这样可避免死锁的产生.ReentrantLock 的主要功能和 synchronized 关键字一致,均是用于多线程的同步.但除此之外,ReentrantLock 在功能上比 synchronized 更为丰富.比如 ReentrantLock 在加锁期间,可响应中断,可设置超时等. ReentrantLock 是我们

经典笔试题:线程通信(使用重入锁(ReentrantLock)和条件队列(Condition)实现线程间通信)

经典笔试题: 1.自定义容器,提供新增元素(add)和获取元素数量(size)方法.2.启动两个线程.线程1向容器中新增10个数据.线程2监听容器元素数量,当容器元素数量为5时,线程2输出信息并终止. package com.gaopeng.programming.test2; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.conc

Java并发(九):重入锁 ReentrantLock

一.ReentrantLock类结构 public class ReentrantLock implements Lock, java.io.Serializable { private final Sync sync; // 锁 大部分功能都是委托给Sync来实现的 abstract static class Sync extends AbstractQueuedSynchronizer {} static final class FairSync extends Sync {} static

重入锁----ReentrantLock

本节主要从下述四个方面介绍重入锁. 1.什么是重入锁? 2.为什么要引用重入锁? 3.重入锁是怎么实现的? 4.分析java并发包中ReentrantLock. 什么是重入锁 重入锁,支持重进入的锁,表示该锁能够支持一个线程对它重复加锁,即线程在获得锁之后再次获取该锁时不会被阻塞. 为什么要引用重入锁? 以子类重写父类方法为例: Mutix是不支持重入的锁.(代码摘抄自<java并发编程的艺术>) 1 import java.util.concurrent.TimeUnit; 2 import

Java可重入锁

锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等等 ) .这些已经写好提供的锁为我们开发提供了便利,但是锁的具体性质以及类型却很少被提及.本系列文章将分析JAVA下常见的锁名称以及特性,为大家答疑解惑. 四.可重入锁: 本文里面讲的是广义上的可重入锁,而不是单指JAVA下的ReentrantLock. 可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响. 在JAV