Java多线程中Lock锁的使用总结

Java多线程中Lock锁的使用总结

什么是Lock?

在Java中,Lock是一种比synchronized更加灵活、功能更加强大的线程同步机制。它可以提供比传统的synchronized更为广泛的锁定操作。

Lock和synchronized的对比

  1. 锁的获取方式

synchronized是隐式获取锁,只要进入synchronized保护的代码段,锁就会自动获得,退出代码段时锁会自动释放。

而在使用Lock时,需要在代码中显式地获得和释放锁,如果没有正确释放锁,就可能导致死锁等问题。

  1. 粒度

使用synchronized时,锁粒度相对较粗,只能在代码块或者方法上进行同步,无法对其中的代码片段进行细粒度的控制。

而使用Lock时可以对某个资源进行单独的加锁和解锁,这就可以避免对整个代码块进行锁定,提高多线程执行的效率。

  1. 等待可中断

在synchronized中,如果等待获取锁的线程一直没有获取到锁,就只能一直等待下去。

而在Lock中,获取锁的操作可以设置等待时间,如果等待时间超过一定的范围仍然没有获取到锁,就可以中断等待,防止死锁的发生。

  1. 公平锁

synchronized是一种非公平锁,锁获取的顺序由系统随机决定,无法保证等待时间最长的线程一定会先获取锁。

而Lock可以通过构造方法设置是否为公平锁,公平锁保证等待时间最长的线程先获取锁,避免了某些线程长时间得不到锁的问题。

Lock的使用示例

示例一:非公平锁

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

public class LockTest {
    private Lock lock = new ReentrantLock(false);
    // false 表示这是一个不公平锁,默认为 false

    public void print() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " get lock");
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public static void main(String[] args) {
        final LockTest lockTest = new LockTest();
        Runnable runnable = () -> {
            System.out.println(Thread.currentThread().getName() + " start");
            lockTest.print();
        };
        new Thread(runnable, "thread1").start();
        new Thread(runnable, "thread2").start();
    }
}

输出结果如下:

thread1 start
thread2 start
thread1 get lock
thread2 get lock

可以看到,在不公平锁的情况下,获得锁的线程是随机的。

示例二:可重入锁

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

public class LockTest {
    private Lock lock = new ReentrantLock();

    public void print() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " get outer lock");
            Thread.sleep(1000);

            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + " get inner lock");
            } finally {
                lock.unlock();
            }

            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println(Thread.currentThread().getName() + " unlock outer lock");
            lock.unlock();
        }
    }
    public static void main(String[] args) {
        final LockTest lockTest = new LockTest();
        Runnable runnable = () -> {
            System.out.println(Thread.currentThread().getName() + " start");
            lockTest.print();
        };
        new Thread(runnable, "thread1").start();
        new Thread(runnable, "thread2").start();
    }
}

输出结果如下:

thread1 start
thread2 start
thread1 get outer lock
thread1 get inner lock
thread1 unlock outer lock
thread2 get outer lock
thread2 get inner lock
thread2 unlock outer lock

在可重入锁的情况下,同一个线程在获得锁后,可以再次获得该锁而不会被阻塞。在上面的示例中,线程1先获得了锁,在获得锁之后,又顺利地获得了一次该锁,因为是同一个线程,所以不会被阻塞。而线程2在获取锁之后也可以顺利地获取第二次锁。这个叫做可重入锁也叫做递归锁。

阅读剩余 65%

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java多线程中Lock锁的使用总结 - Python技术站

(0)
上一篇 2023年5月16日
下一篇 2023年5月16日

相关文章

  • java并发编程实例分析

    我来详细讲解“java并发编程实例分析”的完整攻略。 简介 Java并发编程是高并发、高性能、高可用系统的基石。本文将通过实例分析,详解Java并发编程的三大核心机制:线程、锁、并发容器,帮助读者深入理解Java并发编程的核心原理。 线程 线程基础 Java中通过Thread类来创建线程。线程的状态包括:初始状态、运行状态、等待/阻塞状态、终止状态。线程通常…

    多线程 2023年5月16日
    00
  • Java 中 synchronized的用法详解(四种用法)

    下面是”Java 中 synchronized的用法详解(四种用法)”的完整攻略。 一、synchronized的四个作用 Java中的synchronized关键字可以用于四个方面: 实例方法 静态方法 代码块 class对象锁 二、同步实例方法 用来同步这个实例的所有方法,只允许有一个线程同时访问这个实例的这些方法。需要加在方法前面。 代码示例: pub…

    多线程 2023年5月17日
    00
  • C++ 多线程之互斥量(mutex)详解

    C++ 多线程之互斥量(mutex)详解 什么是互斥量? 在C++中,当多个线程同时访问共享资源时,可能会发生数据冲突或数据竞争的问题,导致程序出错。互斥量就是一种保持互斥、防止数据冲突的机制。在使用互斥量时,只有获取了互斥量的线程才能访问被保护的共享资源,其他线程必须等待。当获取互斥量的线程访问结束并释放互斥量后,其他线程才能继续获取互斥量并访问共享资源。…

    多线程 2023年5月17日
    00
  • java多线程开启的三种方式你知道吗

    当我们需要在Java程序中同时执行多个任务时,可以使用多线程技术来提高程序的效率和响应能力。Java中开启多线程的方式有三种: 继承Thread类并重写run()方法 实现Runnable接口并实现run()方法 实现Callable接口并实现call()方法 1. 继承Thread类并重写run()方法 继承Thread类的方式是最简单也是最常用的开启新线…

    多线程 2023年5月17日
    00
  • JavaScript如何利用Promise控制并发请求个数

    如果我们需要在JavaScript中同时发起多个异步请求,我们可以通过使用Promise.all来实现并发处理。但是,如果我们的请求数量非常庞大,我们可能需要控制并发请求数量,以避免对系统造成过度的压力。下面是一些如何使用Promise来控制并发请求个数的技巧。 控制并发请求个数的方法 限制最大并发数 我们可以使用一个计数器和一个for或者while循环来实…

    多线程 2023年5月16日
    00
  • Java使用代码模拟高并发操作的示例

    我来为你详细讲解Java使用代码模拟高并发操作的示例攻略。 1. 实现思路 高并发是指在同一时间内有大量的请求涌入到系统中,如何处理这些请求成为一个挑战。使用代码模拟高并发操作,则可以帮助我们评估系统在高并发情况下的稳定性和可靠性。实现思路如下: 定义一个接口或者方法,并为该方法添加synchronized关键字,确保该方法同一时间只能被一个线程访问,以模拟…

    多线程 2023年5月16日
    00
  • 关于php 高并发解决的一点思路

    下面是关于PHP高并发解决的一点思路的完整攻略。 一、需求分析 在解决高并发问题之前,我们需要对需求进行分析,具体包括哪些方面: 1.1 并发量 需要先确定项目的具体并发量,这是解决高并发问题的基础。一般可以通过压力测试工具进行测试,将得出的结果作为后续优化的参考。 1.2 瓶颈分析 在确定并发量之后,需要对瓶颈进行分析,主要包括哪些方面: 数据库:主要是分…

    多线程 2023年5月16日
    00
  • Java 多线程之间共享数据

    下面是关于Java多线程之间共享数据的完整攻略: 理解多线程共享数据的概念 多个线程同时对同一份数据进行读写操作时,就会发生数据共享的问题。而这种数据共享会带来一系列的问题,如不一致、竞态条件等。因此在多线程编程中,必须了解数据共享的问题,并采取一些方式来解决它。 解决数据共享的方式 1. 同步控制 同步控制是一种方式,通过它我们可以实现对共享数据的访问控制…

    多线程 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部