java面试题-JUC锁

news2024/11/16 2:56:51

1.介绍下LockSupport?

LockSupport 是 Java 并发包中的一个工具类,用于创建锁和其他同步类的基本线程阻塞原语。它也是 J.U.C 中的一个核心基础类。

相较于 Object.wait()Object.notify()LockSupport 可以更加灵活地对线程进行阻塞和唤醒操作,其主要原理是为每个线程关联一个许可(permit)计数器,该计数器的初始值为 0,当线程调用 LockSupport.park() 方法时,如果许可计数器的值为 0,线程会被阻塞挂起,否则许可计数器的值减 1,线程可以正常执行。如果许可计数器的值大于 0,调用 LockSupport.unpark(Thread t) 方法可以将其值加 1,唤醒线程 t。

在 J.U.C 中,很多并发工具都是基于 LockSupport 来实现的,如 ReentrantLockSemaphore 等,因此 LockSupport 的重要性不言而喻。

2.通过wait/notify实现同步?

在 Java 中,wait() 和 notify() 是 Object 类的两个方法,用于线程之间的通信和同步。可以通过它们实现线程间的协调和互斥。

wait() 方法会让当前线程进入等待状态,并释放对象锁。调用 wait() 方法的线程会进入等待集合中,等待被唤醒。notify() 方法会唤醒等待集合中的某个线程。notifyAll() 方法则会唤醒等待集合中的所有线程。

下面是一个通过 wait/notify 实现同步的示例:

public class Worker {
    private Object lock = new Object();
    private int count = 0;

    public void increment() throws InterruptedException {
        synchronized (lock) {
            // 判断是否已经到达最大值
            while (count >= 100) {
                lock.wait(); // 等待
            }

            // 执行任务
            count++;
            System.out.println("increment: " + count);

            lock.notifyAll(); // 唤醒所有等待线程
        }
    }

    public void decrement() throws InterruptedException {
        synchronized (lock) {
            // 判断是否已经到达最小值
            while (count <= 0) {
                lock.wait(); // 等待
            }

            // 执行任务
            count--;
            System.out.println("decrement: " + count);

            lock.notifyAll(); // 唤醒所有等待线程
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Worker worker = new Worker();

        // 创建多个线程对共享变量进行操作
        Thread t1 = new Thread(() -> {
            try {
                for (int i = 0; i < 50; i++) {
                    worker.increment();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Thread t2 = new Thread(() -> {
            try {
                for (int i = 0; i < 50; i++) {
                    worker.decrement();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        t1.start();
        t2.start();
    }
}

在这个示例中,Worker 类中的 increment() 和 decrement() 方法都包含了一个 while 循环,不断检查共享变量 count 是否满足条件。如果不满足条件,就调用 wait() 方法进入等待状态。如果满足条件,则执行任务,然后调用 notifyAll() 方法唤醒所有等待线程。同时,在主线程中启动多个线程对共享变量进行操作,实现了对共享变量的同步。

3.通过LockSupport的park/unpark实现同步?

LockSupport是一个工具类,提供了阻塞和唤醒线程的方法。park方法可以使当前线程阻塞,而unpark方法可以唤醒一个被阻塞的线程。

使用LockSupport实现同步的一般步骤如下:

  1. 定义一个共享的变量,用于线程之间的通信。

  1. 在生产者线程中,当满足某个条件时,调用LockSupport的unpark方法,唤醒消费者线程。

  1. 在消费者线程中,当满足某个条件时,调用LockSupport的park方法,使线程阻塞等待生产者线程的唤醒。

下面是一个使用LockSupport实现同步的示例代码:

import java.util.concurrent.locks.LockSupport;

public class LockSupportDemo {
    static Thread producerThread, consumerThread;
    static volatile boolean flag = false;
    
    public static void main(String[] args) {
        producerThread = new Thread(() -> {
            System.out.println("Producer is running...");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            flag = true;
            LockSupport.unpark(consumerThread);
            System.out.println("Producer unpark the consumer thread.");
        });
        consumerThread = new Thread(() -> {
            System.out.println("Consumer is waiting...");
            while (!flag) {
                LockSupport.park();
            }
            System.out.println("Consumer received the signal and resumed.");
        });
        producerThread.start();
        consumerThread.start();
    }
}

在这个示例中,主线程启动了一个生产者线程和一个消费者线程。生产者线程首先等待一段时间,然后将共享的变量flag设置为true,并调用LockSupport的unpark方法唤醒消费者线程。消费者线程在开始时调用LockSupport的park方法阻塞等待生产者线程的唤醒。一旦生产者线程唤醒了消费者线程,消费者线程就会检查共享变量flag的值,如果为true,则表示生产者线程已经完成了工作,消费者线程可以结束执行。

4.Thread.sleep()、Object.wait()、Condition.await()、LockSupport.park()的区别?

  1. Thread.sleep()

Thread.sleep() 方法可以让当前线程暂停一段时间,以毫秒为单位,不会释放锁,也不会失去对CPU的控制权。在等待的时间过去之后,线程会重新开始执行。

  1. Object.wait()

Object.wait() 方法会使当前线程等待,直到其他线程调用了相同对象的 notify() 或 notifyAll() 方法。调用 wait() 方法的线程会释放对象锁,以允许其他线程执行 synchronized 方法或块。在线程重新获得锁并被唤醒后,它会重新开始执行。

  1. Condition.await()

Condition.await() 方法是基于 Lock 实现的条件等待方法。与 wait() 不同,await() 必须在获取 Lock 对象之后才能调用。它会释放 Lock 对象并使当前线程等待,直到其他线程调用了 Condition 对象的 signal() 或 signalAll() 方法,唤醒等待的线程并重新获取 Lock 对象以继续执行。

  1. LockSupport.park()

LockSupport.park() 方法可以阻塞当前线程,直到被唤醒。与 wait() 和 await() 不同,park() 方法不需要在 synchronized 块中调用,并且可以在获取锁之前调用。它不会释放任何锁。可以使用 park() 和 unpark() 方法实现更灵活的线程同步。

总的来说,这几种方法的区别在于它们所使用的机制以及对线程和锁的控制权的处理方式。 Thread.sleep() 方法是一个简单的暂停方法,不涉及线程同步或锁;而 Object.wait() 和 Condition.await() 是基于锁的等待机制,需要在 synchronized 块中使用,并与 notify() 或 notifyAll() 方法一起使用。而 LockSupport.park() 和 unpark() 方法可以更灵活地控制线程的暂停和唤醒,可以不需要获取锁并随时使用,但也需要进行合适的配对以避免线程被永久阻塞。

5.如果在wait()之前执行了notify()会怎样?

如果当前的线程不是此对象锁的所有者,却调用该对象的notify()或wait()方法时抛出IllegalMonitorStateException异常;

如果当前线程是此对象锁的所有者,wait()将一直阻塞,因为后续将没有其它notify()唤醒它。

假设有两个线程 A 和 B,它们共享一个对象 obj。线程 A 在 obj 上执行了 obj.wait() 方法并进入了等待状态,此时线程 A 释放了 obj 对象的锁。此时线程 B 获得了 obj 对象的锁并执行了 obj.notify() 方法,因为线程 A 此时已经进入了等待状态,所以线程 B 的通知信号将被记录在 obj 对象的内部,并且在下一次线程 A 获得 obj 对象的锁并执行 obj.wait() 方法时被传递给它,使其从等待状态中恢复并继续执行。

但是,如果线程 B 在线程 A 调用 obj.wait() 方法之前执行了 obj.notify() 方法,此时线程 A 尚未进入等待状态,因此 obj 对象内部并没有记录任何通知信号。在这种情况下,线程 B 的通知信号将被忽略,并且不会被记录。因此,即使线程 A 调用了 obj.wait() 方法,也没有任何通知信号能够被传递给它,因此它仍然会一直处于等待状态。

所以,正确使用 wait() 和 notify() 方法需要注意它们的顺序,以确保线程通信的正确性和避免死锁等问题的发生。

6.如果在park()之前执行了unpark()会怎样?

如果在park()方法之前调用了unpark()方法,这个线程调用park()方法时将会立即返回,并且不会被阻塞。同时,调用unpark()方法会向该线程授予一个许可证,使得该线程在以后调用park()方法时不会被阻塞。这是因为unpark()方法并不需要线程处于阻塞状态才能调用,它只是授予许可证,如果许可证尚未被使用,则该线程在未来调用park()方法时将会立即返回而不会被阻塞。


7.什么是AQS? 为什么它是核心?

AQS(AbstractQueuedSynchronizer)是Java中的一个重要类,它是实现锁、信号量、倒计时计数器等同步机制的基础。AQS提供了一种通用的同步框架,可以很容易地扩展出各种不同类型的同步器,例如ReentrantLock、CountDownLatch、Semaphore等等。

AQS的核心是一个FIFO队列,称为等待队列,它用于保存等待获取锁或许可证的线程。当一个线程想要获取锁或许可证时,如果当前已经被其他线程持有,则该线程将被放入等待队列中,并阻塞线程。当持有锁或许可证的线程释放它们时,AQS会从等待队列中取出一个线程,并将其唤醒,使其可以继续执行。

AQS之所以成为Java并发编程的核心,是因为它提供了一种高效、灵活、可扩展的同步机制。相比较于synchronized关键字,AQS提供的ReentrantLock类可以实现更加灵活的锁,例如支持公平锁和非公平锁、可重入锁、可中断锁等等。此外,AQS还提供了Condition等新的同步工具,可以更加方便地实现线程通信和线程的等待和唤醒。

另外,AQS提供了基于CAS(Compare-And-Swap)操作的原子性操作,这使得AQS在实现同步器时可以避免使用传统的互斥锁机制,从而减少线程阻塞和切换的开销,提高了并发执行的效率。

8.AQS的核心思想是什么?

AQS的核心思想是“状态同步并阻塞”,即通过维护一个状态来协调多个线程的执行,当状态不满足某个条件时,线程会被阻塞,等待状态满足条件时被唤醒。这个状态可以用一个int类型的变量来表示,它的值代表了同步对象的状态,如锁是否被占用、可用资源的数量等等。

在AQS中,通过实现tryAcquire(int arg)和tryRelease(int arg)方法来控制同步对象的状态,并且通过等待队列来维护等待获取同步对象的线程。当一个线程请求获取同步对象时,tryAcquire方法会根据同步对象的状态来决定是否允许该线程获取同步对象。如果tryAcquire返回false,说明同步对象已经被其他线程占用,此时该线程会被加入等待队列并被阻塞。当同步对象的状态发生变化时,如锁被释放,tryRelease方法会将等待队列中的线程唤醒,重新竞争同步对象。

AQS的核心思想使得它可以实现各种不同类型的同步器,例如独占锁、共享锁、信号量、倒计时计数器等等。同时,AQS还支持公平锁和非公平锁、可重入锁、可中断锁等特性,这使得它成为了Java并发编程中非常重要的同步机制。

9.AQS有哪些核心的方法?

  1. acquire(int arg):尝试获取同步状态,如果获取失败则阻塞当前线程。

  1. acquireInterruptibly(int arg):尝试获取同步状态,如果获取失败则阻塞当前线程,并响应中断。

  1. tryAcquire(int arg):尝试获取同步状态,如果获取成功则返回true,否则返回false。

  1. release(int arg):释放同步状态。

  1. acquireShared(int arg):尝试获取共享同步状态,如果获取失败则阻塞当前线程。

  1. tryAcquireShared(int arg):尝试获取共享同步状态,如果获取成功则返回非负数,否则返回负数。

  1. releaseShared(int arg):释放共享同步状态。

这些方法是AQS实现各种同步器的基础,具体的同步器会在这些方法的基础上进行扩展和实现。

10.AQS定义什么样的资源获取方式?

AQS定义了独占模式和共享模式两种资源获取方式。

独占模式是指在同一时刻只能有一个线程获取到资源,其他线程需要等待。比如独占锁就是一种独占模式的同步器。在AQS中,独占模式的资源获取方式由tryAcquire(int arg)tryRelease(int arg)方法实现。

共享模式是指多个线程可以同时获取资源,但有限制条件。比如读写锁就是一种共享模式的同步器,多个线程可以同时读取资源,但只有一个线程可以写入资源。在AQS中,共享模式的资源获取方式由tryAcquireShared(int arg)tryReleaseShared(int arg)方法实现。

11.AQS底层使用了什么样的设计模式?

AQS底层使用了模板方法模式和回调模式这两种设计模式。

模板方法模式是一种行为型设计模式,通过定义一个算法框架,具体的子类可以通过覆盖某些步骤来实现自己的逻辑。AQS的acquirerelease等方法就是模板方法,由具体的子类通过实现tryAcquiretryRelease等方法来定义自己的逻辑。

回调模式是一种事件驱动型设计模式,通过在对象之间建立一种“回调关系”,当一个对象的状态发生变化时,另一个对象会自动得到通知。AQS的等待队列就是通过回调模式来实现的,当一个线程需要等待时,会被封装成一个等待节点,加入等待队列中,并通过回调机制被唤醒。


12什么是可重入,什么是可重入锁? 它用来解决什么问题?

可重入:同一个线程可以多次获得同一个锁或者同步资源,而不会造成死锁或者其他异常情况的发生。Java中的synchronized关键字就是可重入的,同一个线程可以多次获取同一个锁,而不会出现死锁或者锁被其它线程持有的情况。

可重入锁:是一种特殊的锁,它允许同一个线程多次获取同一个锁,并且在释放锁时需要释放相同次数的锁。ReentrantLock就是一种可重入锁的实现,它可以通过lock()方法获取锁,同时可以通过unlock()方法释放锁。如果同一个线程多次获取了该锁,则需要多次调用unlock()方法才能完全释放锁。

可重入锁的作用主要是解决线程的嵌套调用问题,避免死锁的发生。在多线程编程中,经常会出现方法中调用其他方法的情况,如果这些方法需要获取同一把锁,则有可能出现死锁的情况。使用可重入锁可以避免这种情况的发生,提高程序的健壮性和并发性。

13.ReentrantLock的核心是AQS,那么它怎么来实现的,继承吗?

ReentrantLock确实是基于AQS来实现的,但是它并没有通过继承AQS来实现。ReentrantLock实际上是使用了AQS的模板方法模式,在AQS提供的基础上实现了自己的锁逻辑。

具体来说,ReentrantLock在AQS的基础上实现了两个内部类:Sync和FairSync,分别代表非公平锁和公平锁。这两个内部类都继承自AQS,并分别实现了AQS中的tryAcquire和tryRelease等方法,以及自己独有的逻辑。通过这种方式,ReentrantLock实现了自己的锁逻辑,并且可以根据需要选择公平或非公平的锁。

需要注意的是,由于ReentrantLock是使用了AQS的模板方法模式,因此它对AQS的实现细节高度依赖,对于使用者而言,更多地是通过ReentrantLock提供的接口来使用和操作锁,而不是直接使用AQS的接口。

14.ReentrantLock是公平还是非公平锁?

ReentrantLock默认实现的是非公平锁。在创建ReentrantLock对象时,如果不指定参数,则会创建一个非公平锁。如果要创建公平锁,需要通过构造函数的参数指定fair值为true。例如:

ReentrantLock lock = new ReentrantLock(true); // 创建公平锁

ReentrantLock通过内部类FairSync和NonfairSync来实现公平锁和非公平锁,FairSync是公平锁的实现,NonfairSync是非公平锁的实现。FairSync和NonfairSync都继承了AQS同步器类Sync,它们实现了Sync中的tryAcquire方法和tryRelease方法,实现了获取锁和释放锁的逻辑。

15.ReentrantLock和ReentrantReadWriteLock的区别?

ReentrantLock和ReentrantReadWriteLock都是可重入锁,可以支持线程的互斥访问和同步。

不同之处在于,ReentrantLock是独占锁,即同一时间只能有一个线程获得锁并访问共享资源,而ReentrantReadWriteLock支持两种锁:读锁和写锁。在读锁存在的情况下,多个线程可以同时获取读锁,但在写锁存在的情况下,只有一个线程可以获取写锁,其他线程无法获取读锁或写锁。

因此,ReentrantLock适用于互斥访问的场景,ReentrantReadWriteLock适用于读写操作频繁的场景。在读操作远远多于写操作的情况下,使用ReentrantReadWriteLock可以提高并发性和吞吐量。但是,在写操作较多的情况下,如果多个线程争夺写锁,会导致其他线程无法获取读锁或写锁,从而降低并发性能。

16.ReentrantReadWriteLock底层实现原理?

ReentrantReadWriteLock包含了五个内部类,它们之间相互关联,用于实现读写锁的不同语义和行为:

  1. Sync:ReentrantReadWriteLock的基础同步器,包括读锁和写锁的获取、释放等操作,是所有内部类的父类。

  1. NonfairSync:非公平同步器,继承自Sync,实现了非公平的读写锁。

  1. FairSync:公平同步器,继承自Sync,实现了公平的读写锁。

  1. ReadLock:读锁类,包括获取读锁、释放读锁等操作,通过封装Sync类来实现。

  1. WriteLock:写锁类,包括获取写锁、释放写锁等操作,通过封装Sync类来实现。

其中,Sync是ReentrantReadWriteLock的基础同步器,NonfairSync和FairSync分别实现了非公平锁和公平锁,而ReadLock和WriteLock则是对Sync的封装,提供了方便的读锁和写锁的获取和释放方法。这些类之间的关系构成了ReentrantReadWriteLock的内部实现机制。

17.ReentrantReadWriteLock底层读写状态如何设计的?

ReentrantReadWriteLock底层的读写状态是通过一个32位的整型变量来实现的,其中高16位表示读状态,低16位表示写状态。具体来说,高16位的每一位表示是否有读锁被占用,低16位的每一位表示是否有写锁被占用。

18.ReentrantReadWriteLock读锁和写锁的最大数量是多少?

ReentrantReadWriteLock中,读锁和写锁的最大数量取决于32位整型变量中的位数。因为高16位表示读锁的状态,每个位表示一个读锁是否被占用,所以理论上最大支持65535(2的16次方-1)个读锁。同样地,低16位表示写锁的状态,每个位表示一个写锁是否被占用,因此最大支持65535个写锁。

但是,在实际应用中,支持这么多读写锁是没有必要的,也可能会导致性能下降。一般情况下,ReentrantReadWriteLock默认支持最多65535个读锁和一个写锁。但是,这个数量可以通过构造函数进行调整。

19.本地线程计数器ThreadLocalHoldCounter的作用?

ThreadLocalHoldCounter是ReentrantReadWriteLock的一个内部类,用于实现可重入的读锁。每个线程在获取读锁时会调用Sync的tryAcquireShared方法,如果已经持有了读锁,则将对应的计数器加1,如果没有持有读锁,则尝试获取读锁,并创建一个计数器保存到ThreadLocal中。使用ThreadLocalHoldCounter可以避免线程之间的竞争,提高了读锁的性能,并保证了线程安全。

20.写锁的获取与释放是怎么实现的?

ReentrantReadWriteLock中的写锁获取和释放是通过调用AQS的tryAcquiretryRelease方法实现的。当写锁被请求时,会尝试调用tryAcquire获取锁,如果获取锁成功,则更新同步状态并返回true;如果获取锁失败,则返回false。当写锁被释放时,会尝试调用tryRelease释放锁,如果释放成功,则更新同步状态并返回true;如果释放失败,则返回false。在释放写锁的时候,如果当前线程持有的写锁数量变成了0,那么会通过调用fullRelease方法唤醒等待队列中的读线程。

21.读锁的获取与释放是怎么实现的?

ReentrantReadWriteLock中的读锁获取和释放是针对读锁计数器进行操作的。当读锁被请求时,会尝试调用tryAcquireShared获取锁,如果获取锁成功,则更新同步状态并返回非负整数;如果获取锁失败,则返回负整数。当读锁被释放时,会尝试调用tryReleaseShared释放锁,如果释放成功,则更新同步状态并返回true;如果释放失败,则返回false。在释放读锁的时候,如果当前线程持有的读锁数量变成了0,那么会通过调用tryComplete方法唤醒等待队列中的写线程。

22.RentrantReadWriteLock为什么不支持锁升级?

ReentrantReadWriteLock 不支持锁的升级,即不能从读锁直接升级为写锁,原因是升级可能会导致死锁或降低并发性能。

假设有一个线程持有读锁,并且想要升级为写锁,需要先释放读锁,再尝试获取写锁。但是,当此时有其他线程已经获取了写锁,那么升级的线程就会被阻塞,等待写锁释放。此时,如果另外的线程持有了读锁,那么就会出现死锁的情况。

此外,锁的升级还可能导致降低并发性能。因为升级操作需要先释放读锁,再获取写锁,这中间存在一段时间窗口,其他线程可以获取写锁,从而降低了并发性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/360306.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

以学校数据模型为例,掌握在DAS下使用GaussDB

文章目录题目具体操作一、表的创建二、表数据的插入三、数据查询目的&#xff1a; 这里以学校数据库模型为例&#xff0c;介绍GaussDB数据库、表等常见操作&#xff0c;以及SQL语法使用的介绍。题目 假设A市B学校为了加强对学校的管理&#xff0c;引入了华为GaussDB数据库。 在…

如何利用ChatGPT学习量化投资?

引言最近&#xff0c;ChatGPT持续火了很长时间&#xff0c;占领各大热点和头版头条&#xff0c;成为A股开年以来最大的热点之一。ChatGPT是OpenAI开发的一种语言生成模型&#xff0c;可以理解为智能问答机器人。最近围绕量化投资在上面试了很多问题&#xff0c;大部分回答还是很…

基于DSP+FPGA的机载雷达伺服控制系统的硬件设计与开发

机载雷达是以飞机为载体的各种雷达天线的总称&#xff0c;主要用于空中侦察、警戒、保 证航行准确与安全[1]。随着航空航天技术的飞速发展&#xff0c;以及微电子、计算机和高速集 成电路等新型技术在军事领域的广泛应用[2]&#xff0c;各国都研制出了许多新型战机和导弹,机 载…

docsify在线文档支持pdf查看

目录 步骤一&#xff1a;添加插件 步骤二&#xff1a;添加pdf地址 步骤三&#xff1a;成果展示 docsify是一个在github上很好用的文档转换网页的工具&#xff0c;但是大部分情况我们都是使用的markdown文件。最近想把pdf文档也能支持在这上面展示&#xff0c;研究后总结一下…

零信任-微软零信任概念补充(13)

​零信任是一种安全策略。 它不是产品或服务&#xff0c;而是设计和实现以下一组安全原则的方法&#xff1a; 显式验证使用最小特权访问假定数据泄露 零信任的指导原则 显式验证 使用最小特权 访问假定数据泄露 始终根据所有可用的数据点进行身份验证和授权。 使用实时和恰…

内网渗透(四十五)之横向移动篇-WinRM远程执行命令横向移动

系列文章第一章节之基础知识篇 内网渗透(一)之基础知识-内网渗透介绍和概述 内网渗透(二)之基础知识-工作组介绍 内网渗透(三)之基础知识-域环境的介绍和优点 内网渗透(四)之基础知识-搭建域环境 内网渗透(五)之基础知识-Active Directory活动目录介绍和使用 内网渗透(六)之基…

代码随想录【Day20】| 654. 最大二叉树、617. 合并二叉树、700. 二叉搜索树中的搜索、98. 验证二叉搜索树

654. 最大二叉树 题目链接 题目描述&#xff1a; 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下&#xff1a; 二叉树的根是数组中的最大元素。 左子树是通过数组中最大值左边部分构造出的最大二叉树。 右子树是通过数组中最大值右边部分构造出的最…

leaflet 根据一组点的值生成凹包,并在地图上显示(081)

第081个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中根据提供的多个点,利用turf生成凹包。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共88行)安装插件相关API参考:专栏目标示例效果 配置…

1631_MIT 6.828 lab1 HW的部分尝试与总结

全部学习汇总&#xff1a; GreyZhang/g_unix: some basic learning about unix operating system. (github.com) 其实很多尝试我之前自己都做过了&#xff0c;这里就可以直接跳过或者简单提一下。 这个环境的搭建已经完成了&#xff0c;而且早就做了很多尝试了。之前的笔记中记…

设计模式-第3章(设计原则)

设计原则单一职责原则开放-封闭原则依赖倒转原则单一职责原则 设计模式中有一个非常重要的原则 — 单一职责。 单一职责原则&#xff08;SRP&#xff09;&#xff1a;就一个类而言&#xff0c;应该仅有一个引起它变化的原因。 我们在做编程的时候&#xff0c;很自然地就会给一…

「TCG 规范解读」第七章 TPM工作组 TPM 总结

可信计算组织&#xff08;Ttrusted Computing Group,TCG&#xff09;是一个非盈利的工业标准组织&#xff0c;它的宗旨是加强在相异计算机平台上的计算环境的安全性。TCG于2003年春成立&#xff0c;并采纳了由可信计算平台联盟&#xff08;the Trusted Computing Platform Alli…

异步执行结果-Callable、Future、FutureTask

Callable 实现Runnable接口的任务执行没有返回值&#xff0c;如果我们希望线程运算后将结果返回&#xff0c;应该使用Callable。Callable代表有返回值的任务。 class CallTask implements Callable<String> {Overridepublic String call() throws Exception {return Th…

Python基于遥感影像的文件名称将不同文件复制到对应的文件夹中

本文介绍基于Python语言&#xff0c;针对一个文件夹下的大量栅格遥感影像文件&#xff0c;基于其各自的文件名&#xff0c;分别创建指定名称的新文件夹&#xff0c;并将对应的栅格遥感影像文件复制到不同的新文件夹下的方法。 首先&#xff0c;我们来看一下本文需要实现的需求。…

RPC(1)------Java BIO + JDK原生序列化 + JDK动态代理实现

本文跟着MY-RPC-FRamework的代码&#xff0c;根据自己的理解做的笔记&#xff0c;先理解&#xff0c;再学习。 RPC原理 客户端和服务端都可以访问到通用的接口,但是只有服务端有这个接口的实现类&#xff0c;客户端调用这个接口的方式&#xff0c;是通过网络传输&#xff0c;告…

记一次对某假冒征信站点的实战渗透

1. 背景介绍 这次渗透是去年之前的了&#xff0c;原因是当时收到了这个钓鱼短信&#xff0c;这次渗透带有侥幸、偶然性。 后台无脑弱口令 后台无脑文件上传getshell 运气好&#xff0c;直接无脑提权 因为时间问题&#xff0c;本文的记录可能不太完整。 开局之后就是这样的假…

springbatch设置throttle-limit参数不生效

背景描述 当springbatch任务处理缓慢时&#xff0c;就需要使用多线程并行处理任务。 参数throttle-limit用于控制当前任务能够使用的线程数的最大值。 调整throttle-limit为10时&#xff0c;处理线程只有8&#xff0c;再次增大throttle-limit值为20&#xff0c;处理线程依旧为…

make、Makefile项目自动化构建工具

环境&#xff1a;centos7.6&#xff0c;腾讯云服务器Linux文章都放在了专栏&#xff1a;【Linux】欢迎支持订阅&#x1f339;前言自动化构建工具是干什么的呢&#xff1f;主要是为了让我们对指令进行一些设置&#xff0c;就比如说&#xff0c;假如一个项目里有很多个源文件&…

Web3的“陨落”,西下与东升

文/尹宁出品/陀螺研究院极富传奇色彩的Web3似乎正在陨落。去年的Web3&#xff0c;在人声沸腾中讲着下一代互联网摄人心魄的故事&#xff0c;传统资本大刀阔斧般迈入&#xff0c;大厂青年以自由为名掘金&#xff0c;Web3一度成为资本造神新概念。根据Messari 统计,2022 年Web3 V…

如何开发微信小程序呢

也许很多人对小程序&#xff0c;H5程序&#xff0c;Vue&#xff0c;网页程序&#xff0c;PC端程序认识比较模糊&#xff0c;因为这些跨度非常的大&#xff0c;很少人会一次性全部接触&#xff0c;甚至只是听说过&#xff0c;并不了解其中的关系&#xff0c;下面我来厘清他们的关…

传闻腾讯引进Quest 2?我觉得可行性很低

根据36kr最新消息称&#xff0c;腾讯XR团队解散后&#xff0c;确定不碰XR硬件领域&#xff0c;但并未完全放弃XR规划&#xff0c;将转变思路和玩法&#xff0c;业内消息称腾讯计划引进Meta旗下Quest 2 VR一体机。消息称&#xff0c;该计划在2022年11月份XR部门负责人沈黎走后便…