Java 中的Lock锁对象(ReentrantLock/ReentrantReadWriteLock)详解

2023-11-15

目录

1、Lock Objects 详解

2、Java 中的 Lock Objects 的实现原理

3、ReentrantLock 详解

4、ReentrantReadWriteLock 详解

5、Lock锁的等待和唤醒

6、Lock 和 synchronized 的异同


1、Lock Objects 详解

        Java 中的 Lock Objects 是用于线程同步的机制,它们允许多个线程同时访问共享资源,并确保线程安全。与 synchronized 块相比,Lock Objects 提供了更多的灵活性和控制权

        Lock Objects 可以分为两种类型:ReentrantLock 和 ReentrantReadWriteLock。

  • ReentrantLock 是一种互斥锁,它允许同一线程对共享资源进行重入,即该线程在获得锁后可以再次获得该锁而不被阻塞。
  • ReentrantReadWriteLock 由一个读锁和一个写锁组成,它允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。

        以下是使用 ReentrantLock 实现线程同步的示例:

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

public class SharedResource {
    private final Lock lock = new ReentrantLock();
    private int value;

    public void increment() {
        lock.lock(); // 获取锁
        try {
            value++;
        } finally {
            lock.unlock(); // 释放锁
        }
    }

    public int getValue() {
        lock.lock(); // 获取锁
        try {
            return value;
        } finally {
            lock.unlock(); // 释放锁
        }
    }
}

        在上面的示例中,SharedResource 类具有一个私有的 ReentrantLock 对象 lock,并且在 increment() 和 getValue() 方法中都使用了该锁来保证线程安全。在 increment() 方法中,线程会获取锁,并对共享变量 value 进行递增操作,最后释放锁。在 getValue() 方法中,线程会获取锁,返回共享变量 value 的值,最后释放锁。

        使用 Lock Objects 的好处在于它们提供了更细粒度的控制,例如可以指定锁的公平性、超时时间等。同时,与 synchronized 块不同,Lock Objects 还提供了 tryLock() 方法,该方法会尝试获取锁,并立即返回结果。如果锁已被其他线程持有,则返回 false。这样,我们可以在等待锁的过程中做一些其他的操作,而不是一直阻塞等待锁的释放// 利用等待时间

        // Lock对象相对于隐式锁(synchronized)的最大优点是它们能够退出获取锁的尝试。

什么情况下使用 ReentrantLock?

        需要使用 ReentrantLock 的三个独有功能时(等待可中断,实现公平锁,条件通知)

2、Java 中的 Lock Objects 的实现原理

        Java 中的 Lock Objects 实现原理主要依赖于 Java 的 AQS(AbstractQueuedSynchronizer)框架。AQS 是 Java 并发包中的一个基础框架,它提供了一种同步机制,允许自定义同步器的实现,同时提供了可重入锁和条件变量等常见的同步机制的实现。

        ReentrantLock 和 ReentrantReadWriteLock 都是基于 AQS 实现的。它们的实现基本上都是通过维护一个等待队列,将线程放入等待队列中来实现线程同步的。// Semaphore、CountDownLatch 和 CyclicBarrier 等也是基于AQS 实现的

        当一个线程尝试获取锁时,它会调用 Lock 对象的 lock() 方法。如果此时锁没有被其他线程占用,则该线程将成功获取到锁,否则该线程将进入等待队列中等待。当锁被释放时,等待队列中的线程将被唤醒,竞争锁的机会被重新分配。ReentrantLock 还支持可重入,即同一线程可以多次获取同一把锁而不被阻塞,这是通过维护一个计数器来实现的。// 可重入机制的实现

        ReentrantReadWriteLock 的实现原理与 ReentrantLock 类似,但它采用了一种更加灵活的方式来支持读写操作的并发性。它维护了一个读锁和一个写锁,多个线程可以同时持有读锁,但只能有一个线程持有写锁。当有线程获取写锁时,读锁将被阻塞,直到写锁释放。当有线程获取读锁时,如果当前有线程持有写锁,则读锁将被阻塞,直到写锁释放。当有线程获取读锁时,如果当前没有线程持有写锁,则读锁将立即被获取,读锁计数器加一,表示当前有一个线程持有读锁。

        Lock Objects 的实现原理比 synchronized 块更为复杂,但由于它们提供了更高的灵活性和控制力,因此在一些高并发场景下更为适用。但需要注意的是,由于 Lock Objects 的实现较为复杂,使用不当可能会带来一些潜在的问题,例如死锁、竞态条件等。因此,在使用 Lock Objects 时需要谨慎并严格遵守最佳实践。

3、ReentrantLock 详解

        ReentrantLock 是 Java 并发包中提供的一种可重入的独占锁,它可以用来代替 synchronized 关键字进行同步操作。与 synchronized 关键字相比,ReentrantLock 提供了更多的扩展功能,例如可以中断等待锁的线程、可以尝试非阻塞地获取锁、可以限时地等待锁等

        ReentrantLock 的基本使用方法如下:

        (1)创建 ReentrantLock 对象:

Lock lock = new ReentrantLock();

        (2)在需要同步的代码块前后加上 lock() 和 unlock() 方法:

lock.lock();
try {
    // 同步代码块
} finally {
    lock.unlock();
}

        在使用 ReentrantLock 进行同步时,需要注意以下几点:

  1. ReentrantLock 是可重入锁,即同一个线程可以多次获取同一把锁,这样可以避免死锁的发生。但是,要注意在每次获取锁后要及时释放锁,否则会导致其他线程无法获取到锁而发生死锁。
  2. 当使用 ReentrantLock 进行同步时,需要显式地调用 lock() 方法来获取锁,然后在 finally 块中调用 unlock() 方法释放锁。如果在加锁之后没有正确释放锁,就会导致其他线程无法获取到锁而一直处于等待状态。
  3. ReentrantLock 提供了 tryLock() 方法来尝试非阻塞地获取锁,如果获取成功就返回 true,否则返回 false。这个方法可以用来避免线程因为获取不到锁而一直阻塞等待的情况,从而提高程序的效率。
  4. ReentrantLock 还提供了 lockInterruptibly() 方法来支持中断等待锁的线程的操作。如果一个线程正在等待获取锁的过程中,另外一个线程调用了该线程的 interrupt() 方法,那么该线程就会抛出 InterruptedException 异常,从而退出等待状态。
  5. ReentrantLock 还提供了 tryLock(long time, TimeUnit unit) 方法来支持限时等待锁的操作。如果在指定的时间内无法获取到锁,就会返回 false,否则返回 true。这个方法可以用来避免线程因为等待锁而一直阻塞的情况,从而提高程序的效率。

        ReentrantLock 是一个非常实用的锁,它提供了更多的扩展功能和更好的性能表现,可以在多线程编程中发挥很大的作用。但是,在使用 ReentrantLock 时也需要注意正确地使用和释放锁,以避免出现死锁等问题。// 使用Lock对象最应该注意的就是需要手动释放锁

4、ReentrantReadWriteLock 详解

        ReentrantReadWriteLock 是 Java 并发包中提供的一种锁机制,它支持读写锁分离的机制,允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。它实现了 Lock 接口,因此可以作为替代 synchronized 关键字的锁机制。

        ReentrantReadWriteLock 由两个锁组成:读锁和写锁。读锁可以被多个线程同时获取,但是写锁必须独占,也就是说,在任意时刻只能有一个线程获取到写锁。// 一个资源被读锁占据,必须要等待改资源的所有读锁都释放,才能够获取写锁去写数据。

        ReentrantReadWriteLock 的主要特点包括:

  1. 支持多个读线程同时访问共享资源,从而提高并发性能。
  2. 写操作是互斥的,只允许一个线程进行写操作,从而保证数据一致性和安全性。
  3. 支持重入,即同一线程可以多次获取读锁或写锁。
  4. 支持锁降级,即一个线程先获取了写锁,然后再获取读锁,最后释放写锁,这样可以避免线程阻塞,提高并发性能。

        使用 ReentrantReadWriteLock 时需要注意以下几点:

  1. 写锁必须独占,因此如果读线程很多,可能会导致写线程一直等待,从而影响性能。
  2. 写锁可能导致饥饿现象,即某些读线程可能永远无法获取到读锁。
  3. 由于 ReentrantReadWriteLock 是基于内部类 Sync 实现的,因此在使用时需要注意 Sync 类中的方法和属性的访问权限。

        下面是一个示例代码:

public class ReadWriteLockDemo {
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private final List<String> data = new ArrayList<>();
    
    public void readData() {
        lock.readLock().lock();
        try {
            // 读取共享数据
            System.out.println("read data: " + data);
        } finally {
            lock.readLock().unlock();
        }
    }
    
    public void writeData(String newData) {
        lock.writeLock().lock();
        try {
            // 写入共享数据
            data.add(newData);
            System.out.println("write data: " + newData);
        } finally {
            lock.writeLock().unlock();
        }
    }
}

        在上面的示例中,readData()方法获取读锁并读取共享数据,writeData()方法获取写锁并写入共享数据。注意,在获取锁之后,需要在finally语句块中释放锁,以确保锁总是能被正确释放。

        ReentrantReadWriteLock的使用可以提高并发性能,特别是在读操作比写操作更频繁的场景中。但是,它也需要更多的内存和处理器时间来维护状态信息。在使用时需要根据实际场景选择适合的锁机制。

        ReentrantReadWriteLock 的锁降级

        锁降级是指先获取写锁,然后再获取读锁,最后释放写锁的过程。在这个过程中,线程可以先访问共享资源,然后放弃写权限,转而访问读资源。这样可以避免写操作期间读操作的阻塞,提高并发性能。// 由写锁降为读锁,释放写锁后,仍然持有读锁

        下面是一个示例代码:

public class LockDowngradeDemo {
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private final List<String> data = new ArrayList<>();

    public void writeData(String newData) {
        lock.writeLock().lock();
        try {
            // 写入共享数据
            data.add(newData);
            System.out.println("write data: " + newData);

            // 获取读锁
            lock.readLock().lock();
        } finally {
            // 释放写锁
            lock.writeLock().unlock();
        }
    }

    public void readData() {
        lock.readLock().lock();
        try {
            // 读取共享数据
            System.out.println("read data: " + data);
        } finally {
            // 释放读锁
            lock.readLock().unlock();
        }
    }
}

        在上面的示例中,writeData()方法先获取写锁,然后写入共享数据。接着,它获取读锁,释放写锁,这样就实现了锁降级。最后,readData()方法获取读锁并读取共享数据。

        需要注意的是,在锁降级的过程中,线程必须先获取写锁,然后再获取读锁,这是因为读锁是共享锁,可以被多个线程同时持有。如果先获取读锁,再获取写锁,那么写锁就会一直被阻塞,可能导致死锁的发生。

        另外,在实现锁降级的过程中,需要注意锁的释放顺序,即先释放写锁再释放读锁。这是因为写锁是独占锁,不能被多个线程同时持有,而读锁是共享锁,可以被多个线程同时持有。如果先释放读锁,可能会导致其他线程获取读锁而阻塞,无法释放写锁。因此,必须先释放写锁,再释放读锁。

        锁降级过程需要注意的是,释放完写锁后,线程仍然持有读锁,如果此时读锁不释放,其他线程获取写锁时,将会被一致阻塞。下列程序演示了这一过程

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class LockDowngradeDemo {

    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private final List<String>           data = new ArrayList<>();

    public void writeData(String newData) {
        lock.writeLock().lock();
        try {
            // 写入共享数据
            data.add(newData);
            System.out.println(Thread.currentThread().getName() + "-write data: " + newData);

            // 获取读锁
            lock.readLock().lock();
        } finally {
            // 释放写锁,此时线程仍持有读锁
            lock.writeLock().unlock();
            // 此处如果不释放读锁,其他线程获取写锁时将被阻塞,放开此段代码查看输出的区别
//            lock.readLock().unlock();
        }
    }

    public void readData() {
        lock.readLock().lock();
        try {
            // 读取共享数据
            System.out.println(Thread.currentThread().getName() + "-read data: " + data);
        } finally {
            // 释放读锁
            lock.readLock().unlock();
        }
    }

    public static class LockDowngradeTask implements Runnable {

        private LockDowngradeDemo downgradeDemo;

        private String writeData;

        public LockDowngradeTask(LockDowngradeDemo downgradeDemo, String writeData) {
            this.downgradeDemo = downgradeDemo;
            this.writeData     = writeData;
        }

        @Override
        public void run() {
            downgradeDemo.writeData(writeData);
            downgradeDemo.readData();
        }
    }

    public static void main(String[] args) {
        LockDowngradeDemo downgradeDemo = new LockDowngradeDemo();
        LockDowngradeTask task1 = new LockDowngradeTask(downgradeDemo, "write a data");
        LockDowngradeTask task2 = new LockDowngradeTask(downgradeDemo, "write another data");
        new Thread(task1, "thread-1").start();
        new Thread(task2, "thread-2").start();
    }
}

        如果只是释放写锁,不释放读锁,线程2获取写锁时,将一直被阻塞。输出结果如下:

thread-1-write data: write a data
thread-1-read data: [write a data]

5、Lock锁的等待和唤醒

        在Java中,Lock锁的等待和唤醒机制是由Condition对象实现的。Condition对象提供了类似于Object的wait和notify方法的等待和唤醒机制。

        Lock锁中的Condition对象可以通过Lock对象的newCondition方法创建。线程可以通过调用Condition的await方法来等待某个条件满足,然后通过调用Condition的signal方法来唤醒等待在该条件上的线程。

        下面是一个使用Lock的等待和唤醒的示例代码:

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

public class LockConditionExample {
    private final Lock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();
    private volatile boolean flag = false;

    public void waitForFlag() throws InterruptedException {
        lock.lock();
        try {
            while (!flag) {
                condition.await();
            }
        } finally {
            lock.unlock();
        }
    }

    public void setFlag() {
        lock.lock();
        try {
            flag = true;
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        LockConditionExample example = new LockConditionExample();
        new Thread(() -> {
            try {
                example.waitForFlag();
                System.out.println("Thread 1 is finished");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
        new Thread(() -> {
            try {
                Thread.sleep(1000);
                example.setFlag();
                System.out.println("Thread 2 is finished");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
    }
}

        在这个示例中,我们定义了一个Lock和一个Condition。waitForFlag方法获取锁,如果flag为false,则在Condition上等待。setFlag方法设置flag为true并唤醒在Condition上等待的线程。

        在main方法中,我们创建了两个线程。第一个线程等待flag变为true,第二个线程在1秒后设置flag为true并唤醒第一个线程。当第一个线程被唤醒后,它将输出"Thread 1 is finished"。

        这个示例展示了如何使用Lock和Condition实现线程之间的等待和唤醒机制。需要注意的是,在使用await()和signal()方法时,必须先获取到锁对象才能调用这些方法,否则会抛出IllegalMonitorStateException异常。// 这点和object类中的wait()和notify()方法类似

6、Lock 和 synchronized 的异同

        Lock 和 synchronized 的对比:

特性 Lock     synchronized
本质 Lock锁是接口 synchronized是关键字
作用范围 只能作用于代码块上 作用于方法和代码块上
底层  基于AQS,FIFO先进先出队列实现的 基于object Monitor对象锁来实现的
支持  支持公平锁和非公平锁  只支持非公平锁
加锁方式 非阻塞式加锁,并且支持可中断式加锁,支持超时时间加锁 阻塞式加锁
加锁和解锁 Lock锁有一个同步队列和支持多个等待队列(condition) 在加锁和解锁时,只有一个同步队列和一个等待队列
等待和唤醒 lock锁使用的是condition接口的await()和signal()方法 使用的是object类中的wait()和notify()方法

(1)Lock锁需要用到内核模式吗?

        Java 中的 Lock 锁通常不需要使用内核模式。相比于 synchronized 关键字,Lock 锁更多地依赖于用户空间的 CAS(Compare and Swap)操作和 volatile 关键字来实现锁的操作。CAS 操作是一种原子操作,它可以在不使用锁的情况下实现线程同步。volatile 关键字可以保证变量的可见性,从而保证锁的状态对所有线程可见。

        具体地说,Java 中的 Lock 锁通常采用的是自旋锁的方式,即线程不断地尝试获取锁,如果获取失败就不断重试,直到获取到锁为止。这种方式避免了线程进入内核模式从而造成的性能损失。只有当自旋的次数达到一定的阈值,或者发现当前锁已经被其他线程占用时,线程才会进入内核模式进行等待。

        需要注意的是,在某些特定的情况下,Java 中的 Lock 锁可能会使用到内核模式。例如,如果一个线程在尝试获取锁的过程中遇到了饥饿现象(即一直获取不到锁),那么系统可能会采用类似于睡眠的方式,让该线程暂时让出 CPU 资源,等待一段时间后再次尝试获取锁。这个过程可能会涉及到内核模式的操作。但是,这种情况只是极少数的情况,通常情况下 Java 中的 Lock 锁不会使用到内核模式。

(2)Lock锁比synchronized 的性能要高吗?

        在某些情况下,使用 Lock 锁比 synchronized 关键字可以获得更高的性能,但并不是在所有情况下都是如此。具体来说,Lock 锁相对于 synchronized 关键字的优势主要体现在以下两个方面:

  1. 粒度控制:Lock 锁提供了更细粒度的控制,可以灵活地控制锁的获取和释放。相比之下,synchronized 关键字只能对整个方法或者整个代码块进行加锁,无法进行更细粒度的控制。
  2. 非阻塞加锁:在某些情况下,Lock 锁可以采用非阻塞的方式进行加锁,避免了线程进入内核模式造成的性能损失。相比之下,synchronized 关键字的加锁过程是阻塞式的,一旦一个线程获取到了锁,其他线程就必须等待这个线程释放锁才能继续执行。

        需要注意的是,Lock 锁相对于 synchronized 关键字也存在一些劣势,例如:

  1. 代码复杂度:相对于 synchronized 关键字,Lock 锁的使用方法更为复杂,需要显式地获取和释放锁。
  2. 内存消耗:Lock 锁需要占用额外的内存空间来存储锁对象等信息。
  3. 可读性:Lock 锁的代码相对于 synchronized 关键字可能更加冗长,可读性稍差。

        因此,在实际开发中应该根据具体情况选择合适的锁机制。一般来说,如果只是简单的线程同步,使用 synchronized 关键字已经足够;如果需要更细粒度的控制或者需要避免线程阻塞,可以考虑使用 Lock 锁。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 中的Lock锁对象(ReentrantLock/ReentrantReadWriteLock)详解 的相关文章

  • 源码分析【ReentrantLock】原理

    ReentrackLock底层原理 ReentrackLock介绍 非公平锁VS公平 非公平锁 公平锁 可打断VS不可打断 不可打断 默认 可打断模式 锁超时 条件变量 如何在synchronized和ReentrantLock之间进行选择
  • Java并发编程:Copy-On-Write机制详解

    前言 在多线程并发访问共享数据时 可能会出现并发问题导致程序崩溃 数据异常等情况 为了避免这些问题 Java中提供了多种并发控制方法 其中Copy On Write COW 机制就是一种常用的技术 本文将详细介绍COW机制的概念 如何保证线
  • 并发编程系列之线程简介

    前言 前几天我们把Java内存模型介绍了下 大家对JMM也有所认识了 从今天我们就开始走进一个我们天天挂在嘴边 听在耳边的东西 线程 对于线程相信大家都不会陌生 当然也有很多小伙伴在开发中或多或少的使用到线程 即使你没有使用过 但是并不代表
  • 并发编程系列——6线程池核心原理分析

    学习目标 线程池的作用 jdk给我们提供了哪几种常用线程池 线程池有哪几大核心参数 线程池的拒绝策略有哪些 线程中阻塞队列的作用 线程池的工作流程 线程池的设计思维 线程池中的阻塞队列如果用默认的 会有哪些问题 线程池的工作状态有哪些 线程
  • 场景题之最快返回结果

    场景题之最快返回结果 问题描述 输入中文 最快从百度翻译 谷歌翻译 有道翻译获取结果返回 代码实现 思路 采用CompletableFuture实现 多个CompletableFuture可以串行执行 也可以并行执行 其中anyOf 方法只
  • 并发编程(线程)面试题总结2022

    目录 并发编程三要素是什么 在 Java 程序中怎么保证 多线程 的运行安全 什么是多线程 多线程的优劣 形成死锁的四个必要条件是什么 创建线程有哪几种方式 继承 Thread 类 实现 Runnable 接口 实现 Callable 接口
  • 【并发】并发

    并发 进程和线程 进程 资源分配的基本单位 可以理解为在内存中运行的程序 每个进程都有独立的内存空间 一个进程包含多个线程 线程 任务执行的基本单位 负责进程中任务的执行 每个线程共享进程的内存空间 一个线程使用时 其他线程必须等待 用户
  • 并发策略之分工原则

    本文主要思想来自 Java虚拟机并发编程 薛笛 译 为什么要用并发 并发是再在有限的资源下提高性能的有效手段 当然现在互联网环境下并发访问的现象也比比皆是 但是本文并不涉及处理并发访问 而是使用并发手段解决复杂任务的策略 另外关于并发和并行
  • C/C++基于线程的并发编程(二):线程安全和线程锁

    线程安全 所谓线程安全不是指线程的安全 而是指内存的安全 线程是由进程所承载 所有线程均可访问进程的上下文 意味着所有线程均可访问在进程中的内存空间 这也是线程之间造成问题的潜在原因 当多个线程读取同一片内存空间 变量 对象等 时 不会引起
  • BlockingQueue、ArrayBlockingQueue、LinkedBlockingQueue原理分析

    阻塞队列与非阻塞队 阻塞队列与普通队列的区别在于 当队列是空的时 从队列中获取元素的操作将会被阻塞 或者当队列是满时 往队列里添加元素的操作会被阻塞 试图从空的阻塞队列中获取元素的线程将会被阻塞 直到其他的线程往空的队列插入新的元素 同样
  • 在Windows下使用MingGW[GCC+OpenMP]和CodeBlocks开发多核应用基本环境配置

    转自 http blog csdn net danny xcz article details 3332251 从06年开始 多核开发已经越来越多的成为所有应用设计必须考虑的问题 我使用MingGW CodeBlocks来测试OpenMP多
  • shell编程笔记3--shell并发

    shell编程笔记3 shell并发 shell编程笔记3 shell并发 介绍 并发方法 1 简单后台方式 2 普通控制并发量方式 3 通过管道控制并发量 参考文献 shell编程笔记3 shell并发 介绍 在shell中适当使用并发功
  • Java并发编程实战——并发容器之ConcurrentHashMap(JDK 1.8版本)

    文章目录 ConcurrentHashmap简介 从关键属性及类上来看ConcurrentHashMap的结构 put 方法管中窥豹 CAS关键操作 ConcurrentHashmap简介 在使用HashMap时在多线程情况下扩容会出现CP
  • Java 线程池的submit的使用与分析.md

    在Java5以后 通过Executor来启动线程比用Thread的start 更好 在新特征中 可以很容易控制线程的启动 执行和关闭过程 还能使用线程池的特性 上一篇我们介绍了线程池的基本用法和特性 我们用的最多的是ExecutorServ
  • 并发编程系列之原子操作实现原理

    前言 上节我们讲了并发编程中最基本的两个元素的底层实现 同样并发编程中还有一个很重要的元素 就是原子操作 原子本意是不可以再被分割的最小粒子 原子操作就是指不可中断的一个或者一系列操作 那么今天我们就来看看在多处理器环境下Java是如何保证
  • Java 中的Lock锁对象(ReentrantLock/ReentrantReadWriteLock)详解

    目录 1 Lock Objects 详解 2 Java 中的 Lock Objects 的实现原理 3 ReentrantLock 详解 4 ReentrantReadWriteLock 详解 5 Lock锁的等待和唤醒 6 Lock 和
  • CUDA编程问题记录:能否用CPU多线程调用CUDA核函数

    问题 能否在主机端创建CPU多线程 在每个线程里调用设备端核函数的caller函数 进而实现进一步的并行运行 例如有5张图片 对于每张图片都有N个GPU线程对其进行像素操作 但是此时是逐一对这5张图片处理的 想在主机端创建5个CPU线程 每
  • 说说JUC三个类:CountDownLatch,CyclicBarrier和Semaphore

    目录 CountDownLatch CyclicBarrier Semaphore 总结 在JUC中 有三个工具类来辅助我们进行并发编程 分别是 CountDownLatch CyclicBarrier和Semaphore CountDow
  • 线程的状态与切换

    Java中的线程的生命周期大体可分为5种状态 1 新建 初始化 NEW 新创建了一个线程对象 2 可运行 RUNNABLE 线程对象创建后 其他线程 比如main线程 调用了该对象的start 方法 该状态的线程位于可运行线程池中 等待被线
  • 并发编程4 - 线程状态、死锁及ReentrantLock

    文章目录 一 再述线程状态转换 二 多把锁与线程活跃性问题 1 多把锁 2 活跃性 三 ReEntrantLock 1 基本用法 2 可重入 3 可打断 4 锁超时 5 公平锁 6 条件变量 一 再述线程状态转换 情况1 New RUNNA

随机推荐

  • activiti7-2-流程定义、实例、任务查询、任务处理、压缩部署、定义查询、定义删除、定义资源查询、历史信息查询

    我是一个目录 1 流程定义 1 1 绘制流程图 1 2 简单介绍API和原理机制 1 2 1 API 1 2 2 原理机制 1 3 流程定义部署测试类 1 4 分析影响的表 2 流程实例 2 1 启动流程实例 2 2 分析影响的表 3 任务
  • windows 2003 传真服务器高级配置与管理

    这里我和大家一起来了解一下传真服务器的高级配置与管理 在上一博文中我说了 我们要实现电子邮件的通知和传真服务的控制台管理已经日志分析的功能 首先介绍的是windows 2003自带的传真服务器提供了SMTP支持传真到达通知的功能和传真发送成
  • 备战2024秋招面试题-最左匹配原则、索引失效情况、算法(最长回文子串)

    前言 textcolor Green 前言 前言 快秋招了 那么这个专栏就专门来记录一下 同时呢整理一下常见面试题 部分题目来自自己的面试题 部分题目来自网络整理 给我冲 学习目标 面试题 算法题 完成 学习目标 最左匹配原则 索引失效情况
  • 在微信小程序里面使用npm

    在微信小程序里面使用npm 从小程序基础库版本 2 2 1 或以上 及开发者工具 1 02 1808300 或以上开始 小程序支持使用 npm 安装第三方包 为了扩展微信小程序的功能 现在允许微信小程序使用npm 来扩展我们的功能 使用很简
  • 计算机三级网络技术备考复习资料

    以前用到的资料 偶尔翻翻还挺有用 记录之 第一章 计算机基础 分析 考试形式 选择题和填空题 6个的选择题和2个填空题共10分 都是基本概念 1 计算机的四特点 有信息处理的特性 有广泛适应的特性 有灵活选择的特性 有正确应用的特性 此条不
  • vue 测试环境 生产环境 线上环境 环境配置

    var env config dev name dev api url location protocol 10 0 0 230 80 api server url location protocol narcissus ih2ome cn
  • cpp 5.7

    5 7 include
  • 谈谈 Docker Volume 之权限管理(一)

    Volume数据卷是Docker的一个重要概念 数据卷是可供一个或多个容器使用的特殊目录 可以为容器应用存储提供有价值的特性 持久化数据与容器的生命周期解耦 在容器删除之后数据卷中的内容可以保持 Docker 1 9之后引进的named v
  • 1056 Mice and Rice (25 分)

    题目 题解 模拟 看懂题 自己实现就OK了 代码 include
  • pytorch构造可迭代的Dataset——IterableDataset(pytorch Data学习二)

    如果是可以一次性加载进内存的数据 上一篇博客 pytorch 构造读取数据的工具类 Dataset 与 DataLoader pytorch Data学习一 已经足以应付了 但是很多时候数据集较大 比如6个T 的数据 没办法直接加载 因此这
  • 如何理解时钟周期及公式CPU执行时间 = CPU时钟周期数/主频

    因为用OneNote制作的 公式复制不过来太麻烦 直接截图了 下面看一下时钟周期的定义 CPU时钟周期 通常为节拍脉冲或T周期 即主频的倒数 它是CPU中最小的时间单位 每个动作至少需要一个时钟周期 其实就是把前面的式子中的秒这个单位忽略掉
  • Python3 安装 MySQL-python错误解决

    目的 解决 python3 利用 pip 安装 MySQL python 问题 参考错误信息 apps svr python3 bin pip3 install MySQL python Collecting MySQL python Us
  • shuqian

    h1 Bookmarks h1 dl p p dt h3 h3 dt dl
  • 【Nexus】安装配置与使用

    1 为什么使用Nexus 如果没有私服 我们所需的所有构件都需要通过maven的中央仓库和第三方的Maven仓库下载到本地 而一个团队中的所有人都重复的从maven仓库下 载构件无疑加大了仓库的负载和浪费了外网带宽 如果网速慢的话 还会影响
  • Constructing Roads In JGShining's Kingdom

    点击打开链接 Problem Description JGShining s kingdom consists of 2n n is no more than 500 000 small cities which are located i
  • Python3+pyshark捕获数据包并保存为文件

    一 直接使用wireshark捕获数据包并保存为文件 可以使用wireshark通过图形界面的操作来实现捕获数据包并保存为文件 wireshark默认捕获的数据包保存为临时文件 如果最后退出时不选择保存那么临时文件将会被删除 可以在 菜单栏
  • 汉明距离(Hamming Distance)

    汉明距离 Hamming Distance 定义 汉明距离以美国数学家理查德 卫斯里 汉明的名字命名 表示两个相同长度的字符串在相同位置上不同字符的个数 用d x y 来表示x和y两个字符串的汉明距离 汉明距离可以用来计算两个文本之间的相似
  • diff和patch命令——Linux命令解析(一)

    个人学习记录使用 一 说明 patch命令和diff命令 往往是要搭配使用的 patch 利用提供的补丁文件 给源文件打补丁 diff 比较两个文件 生成需要修改的补丁文件 二 diff命令 生成补丁文件 1 命令格式 diff optio
  • Cygwin 、MSYS、MinGW 的区别与联系是怎样的?

    讲区别联系之前 我们先看一下这几个东东的前世今生 Cygwin 原 Cygnus 出品 已被红帽收购 目前是 RedHat 名下的项目 项目的目的是提供运行于 Windows 平台的类 Unix 环境 以 GNU 工具为代表 为了达到这个目
  • Java 中的Lock锁对象(ReentrantLock/ReentrantReadWriteLock)详解

    目录 1 Lock Objects 详解 2 Java 中的 Lock Objects 的实现原理 3 ReentrantLock 详解 4 ReentrantReadWriteLock 详解 5 Lock锁的等待和唤醒 6 Lock 和