java并发:Lock、ReentrantLock

Lock是一个接口,提供了无条件的、可轮询的、定时的、可中断的锁获取操作,所有加锁和解锁的方法都是显式的。

包路径是:java.util.concurrent.locks.Lock

核心方法是lock()、unlock()、tryLock()

实现类有ReentrantLock、ReentrantReadWriteLock.ReadLock、ReentrantReadWriteLock.WriteLock

下图展示了Lock接口中定义的方法:

Java中synchronized 和 ReentrantLock 有什么不同?

Java在过去很长一段时间只能通过synchronized关键字来实现互斥,它有一些缺点。比如你不能扩展锁之外的方法或者块边界,尝试获取锁时不能中途取消等。Java 5 通过Lock接口提供了更复杂的控制来解决这些问题。ReentrantLock是Lock的实现类,它拥有与synchronized相同的并发性和内存语义且它还具有可扩展性。

此处我们看一下下面这两段代码,请注意这两种方式的区别:

(1)此处两个方法之间的锁是独立的

package com.test;

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo {
    public static void main(String[] args) {
        final Countx ct = new Countx();
        for (int i = 0; i < 2; i++) {
            new Thread() {
                @Override
                public void run() {
                    ct.get();
                }
            }.start();
        }
        for (int i = 0; i < 2; i++) {
            new Thread() {
                @Override
                public void run() {
                    ct.put();
                }
            }.start();
        }
    }
}

class Countx {

    public void get() {
        final ReentrantLock lock = new ReentrantLock();
        try {
            lock.lock();// 加锁
            System.out.println(Thread.currentThread().getName() + "get begin");
            Thread.sleep(1000L);// 模仿干活
            System.out.println(Thread.currentThread().getName() + "get end");
            lock.unlock(); // 解锁
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void put() {
        final ReentrantLock lock = new ReentrantLock();
        try {
            lock.lock();// 加锁
            System.out.println(Thread.currentThread().getName() + "put begin");
            Thread.sleep(1000L);// 模仿干活
            System.out.println(Thread.currentThread().getName() + "put end");
            lock.unlock(); // 解锁
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行结果如下(每次运行结果都是不一样的,仔细体会一下):

Thread-1get begin
Thread-0get begin
Thread-2put begin
Thread-3put begin
Thread-0get end
Thread-3put end
Thread-1get end
Thread-2put end

(2)此处两个方法之间使用相同的锁

package com.test;

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo {
    public static void main(String[] args) {
        final Countx ct = new Countx();
        for (int i = 0; i < 2; i++) {
            new Thread() {
                @Override
                public void run() {
                    ct.get();
                }
            }.start();
        }
        for (int i = 0; i < 2; i++) {
            new Thread() {
                @Override
                public void run() {
                    ct.put();
                }
            }.start();
        }
    }
}

class Countx {
    final ReentrantLock lock = new ReentrantLock();

    public void get() {
        // final ReentrantLock lock = new ReentrantLock();
        try {
            lock.lock();// 加锁
            System.out.println(Thread.currentThread().getName() + "get begin");
            Thread.sleep(1000L);// 模仿干活
            System.out.println(Thread.currentThread().getName() + "get end");
            lock.unlock(); // 解锁
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void put() {
        // final ReentrantLock lock = new ReentrantLock();
        try {
            lock.lock();// 加锁
            System.out.println(Thread.currentThread().getName() + "put begin");
            Thread.sleep(1000L);// 模仿干活
            System.out.println(Thread.currentThread().getName() + "put end");
            lock.unlock(); // 解锁
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行结果如下(每次运行结果都是一样的):

Thread-0get begin
Thread-0get end
Thread-1get begin
Thread-1get end
Thread-2put begin
Thread-2put end
Thread-3put begin
Thread-3put end
时间: 2024-10-08 14:36:15

java并发:Lock、ReentrantLock的相关文章

Java并发编程 ReentrantLock 源码分析

ReentrantLock 一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大. 这个类主要基于AQS(AbstractOwnableSynchronizer)封装的 公平与非公平锁. 所谓公平锁就是指 在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程,换句话说也就是先被锁定的线程首先获得锁. 非公平锁正好相反,解锁时没有固定顺序. 让我们边分析源代码边学习如何使用该类 先来看一下构造参数,默认

深入java并发Lock一

java有像syncronized这样的内置锁,但为什么还需要lock这样的外置锁? 性能并不是选择syncronized或者lock的原因,jdk6中syncronized的性能已经与lock相差不大. 如果要选择lock的话,会基于lock拥有的几个优点(内置锁所不具备): 1.如果希望当获取锁时,有一个等待时间,不会无限期等待下去. 2.希望当获取不到锁时,能够响应中断 3.当读多,写少的应用时,希望提高性能 4.获取不到锁时,立即返回false.获取到锁时返回true. lock接口定义

java并发 lock锁

Java并发编程:Lock 在上一篇文章中我们讲到了如何使用关键字synchronized来实现同步访问.本文我们继续来探讨这个问题,从Java 5之后,在java.util.concurrent.locks包下提供了另外一种方式来实现同步访问,那就是Lock. 也许有朋友会问,既然都可以通过synchronized来实现同步访问了,那么为什么还需要提供Lock?这个问题将在下面进行阐述.本文先从synchronized的缺陷讲起,然后再讲述java.util.concurrent.locks包

【死磕Java并发】-----J.U.C之重入锁:ReentrantLock

此篇博客所有源码均来自JDK 1.8 ReentrantLock,可重入锁,是一种递归无阻塞的同步机制.它可以等同于synchronized的使用,但是ReentrantLock提供了比synchronized更强大.灵活的锁机制,可以减少死锁发生的概率. API介绍如下: 一个可重入的互斥锁定 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁定相同的一些基本行为和语义,但功能更强大.ReentrantLock 将由最近成功获得锁定,并且还没有释放该锁定的线程所拥

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

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

Java并发编程总结3——AQS、ReentrantLock、ReentrantReadWriteLock

本文内容主要总结自<Java并发编程的艺术>第5章——Java中的锁. 一.AQS AbstractQueuedSynchronizer(简称AQS),队列同步器,是用来构建锁或者其他同步组建的基础框架.该类主要包括: 1.模式,分为共享和独占. 2.volatile int state,用来表示锁的状态. 3.FIFO双向队列,用来维护等待获取锁的线程. AQS部分代码及说明如下: public abstract class AbstractQueuedSynchronizer extend

Java并发基础框架AbstractQueuedSynchronizer初探(ReentrantLock的实现分析)

AbstractQueuedSynchronizer是实现Java并发类库的一个基础框架,Java中的各种锁(RenentrantLock, ReentrantReadWriteLock)以及同步工具类(Semaphore, CountDownLatch)等很多都是基于AbstractQueuedSynchronizer实现的.AbstractQueuedSynchronizer 一般简称AQS,Abstract表示他是一个抽象类,Queued表示他是基于先进先出 FIFO 等待队列实现的,Sy

5、Java并发编程:Lock

Java并发编程:Lock 在上一篇文章中我们讲到了如何使用关键字synchronized来实现同步访问.本文我们继续来探讨这个问题,从Java 5之后,在java.util.concurrent.locks包下提供了另外一种方式来实现同步访问,那就是Lock. 也许有朋友会问,既然都可以通过synchronized来实现同步访问了,那么为什么还需要提供Lock?这个问题将在下面进行阐述.本文先从synchronized的缺陷讲起,然后再讲述java.util.concurrent.locks包

Java并发编程之---Lock框架详解

Java 并发开发:Lock 框架详解 摘要: 我们已经知道,synchronized 是Java的关键字,是Java的内置特性,在JVM层面实现了对临界资源的同步互斥访问,但 synchronized 粒度有些大,在处理实际问题时存在诸多局限性,比如响应中断等.Lock 提供了比 synchronized更广泛的锁操作,它能以更优雅的方式处理线程同步问题.本文以synchronized与Lock的对比为切入点,对Java中的Lock框架的枝干部分进行了详细介绍,最后给出了锁的一些相关概念. 一

【Java并发系列04】线程锁synchronized和Lock和volatile和Condition

img { border: solid 1px } 一.前言 多线程怎么防止竞争资源,即防止对同一资源进行并发操作,那就是使用加锁机制.这是Java并发编程中必须要理解的一个知识点.其实使用起来还是比较简单,但是一定要理解. 有几个概念一定要牢记: 加锁必须要有锁 执行完后必须要释放锁 同一时间.同一个锁,只能有一个线程执行 二.synchronized synchronized的特点是自动释放锁,作用在方法时自动获取锁,任意对象都可做为锁,它是最常用的加锁机制,锁定几行代码,如下: //---