面试小札:闪电五连鞭_5

ops/2024/12/23 22:59:11/

1. 在Java程序中保证多线程的运行安全

 

- 使用synchronized关键字

- 可以修饰方法。例如,当一个方法被声明为 synchronized 时,同一时刻只有一个线程可以访问该方法。比如:

java

public class Counter {

    private int count = 0;

    public synchronized void increment() {

        count++;

    }

    public int getCount() {

        return count;

    }

}

在这个 Counter 类中, increment 方法被 synchronized 修饰。当多个线程访问 increment 方法时,Java会保证同一时刻只有一个线程能够执行该方法内的代码,从而避免了多个线程同时修改 count 变量导致的数据不一致问题。

- 也可以用于代码块。可以指定一个对象作为锁,例如:

java

public class SharedResource {

    private Object lock = new Object();

    private int data;

    public void modifyData(int newData) {

        synchronized (lock) {

            data = newData;

        }

    }

}

这里,只有获得 lock 对象锁的线程才能执行 synchronized 代码块中的 data = newData 语句,这样可以对 data 变量的访问进行控制,保证数据的一致性。

- 使用ReentrantLock类

-  ReentrantLock 是一种可重入锁。它提供了比 synchronized 关键字更灵活的锁机制。例如:

java

import java.util.concurrent.locks.ReentrantLock;

public class BankAccount {

    private double balance;

    private ReentrantLock lock = new ReentrantLock();

    public void deposit(double amount) {

        lock.lock();

        try {

            balance += amount;

        } finally {

            lock.unlock();

        }

    }

}

 

在 BankAccount 类的 deposit 方法中,首先通过 lock.lock() 获取锁,然后在 try - finally 块中执行对 balance 变量的操作。在 finally 块中通过 lock.unlock() 释放锁,这样可以确保锁一定会被释放,即使在操作过程中出现异常。

 

2. 读写锁可用于什么场景中

- 数据读取频繁、写入不频繁的场景

- 例如,在一个缓存系统中,多个线程可能会频繁地读取缓存中的数据,但写入操作(如更新缓存数据)相对较少。使用读写锁(如 ReentrantReadWriteLock )可以允许多个线程同时读取缓存数据,提高读取性能。只有当有线程需要写入数据时,才会排他性地获取写锁,此时其他线程(无论是读线程还是写线程)都需要等待。

 

3. 锁是什么?有什么用?有哪几种锁?

- 锁的定义和作用

- 锁是一种用于控制多个线程对共享资源访问的机制。在多线程环境中,多个线程可能会同时访问和修改共享资源,这可能会导致数据不一致、竞争条件等问题。锁可以确保在同一时刻只有一个(对于排它锁)或多个(对于共享锁)线程能够访问共享资源,从而保证程序的正确性和数据的一致性。

- 锁的种类

- 排它锁(Exclusive Lock)

- 也称为互斥锁。例如, synchronized 关键字在修饰方法或代码块时就是一种排它锁机制。在Java中, ReentrantLock 默认也是排它锁。当一个线程获取了排它锁后,其他线程不能再获取该锁,直到持有锁的线程释放锁。这种锁适用于对共享资源进行修改的操作,如写入数据到数据库、更新文件内容等场景。

- 共享锁(Shared Lock)

- 读写锁中的读锁就是一种共享锁。多个线程可以同时获取共享锁来读取共享资源,但是当有一个线程获取了排它锁(写锁)时,其他线程既不能获取排它锁也不能获取共享锁。这种锁适用于多个线程对共享资源进行读取操作的场景,如读取数据库中的数据、读取配置文件等。

- 可重入锁(Reentrant Lock)

- 像 ReentrantLock 和被 synchronized 修饰的方法或代码块都是可重入的。这意味着一个线程可以多次获取同一个锁。例如,在一个递归调用的方法中,如果该方法被 synchronized 修饰,线程在递归调用过程中可以多次获取该锁而不会发生死锁。

- 自旋锁(Spin Lock)

- 自旋锁是一种比较特殊的锁。当一个线程尝试获取自旋锁而该锁已经被其他线程占用时,这个线程不会立即进入阻塞状态,而是会在一个循环中不断地检查锁是否被释放,这个过程就像线程在“自旋”。自旋锁适用于锁被占用的时间很短的情况,因为它避免了线程在阻塞和唤醒过程中的开销,但如果锁被长时间占用,会浪费CPU资源。

 

4. 什么是死锁?

- 死锁是指两个或多个线程在执行过程中,因争夺资源而造成的一种互相等待的现象。例如,线程A持有资源R1并且等待资源R2,而线程B持有资源R2并且等待资源R1,这样两个线程就会一直等待下去,无法继续执行,导致程序出现停滞状态。

 

5. 怎么防止死锁?

- 破坏死锁产生的必要条件

- 互斥条件:有些资源本身的性质决定了它们在使用时必须是互斥的,比如打印机,在打印一份文档时不能同时被多个任务使用。但对于一些可以共享的资源,如只读的数据结构,可以尽量采用共享访问的方式,避免强制互斥。

- 请求和保持条件:可以采用一次性申请所有资源的策略。例如,一个线程在开始执行任务前,就把它需要的所有资源都申请好,如果无法获取全部资源,就等待,直到所有资源都可用。这样就避免了线程在持有部分资源的情况下又去请求其他资源。

- 不可剥夺条件:可以设置资源的超时机制。如果一个线程长时间占用某个资源而没有释放,系统可以强制剥夺该资源并分配给其他等待的线程。不过这种方式需要谨慎使用,因为可能会导致数据不一致等问题。

- 循环等待条件:可以对资源进行排序。每个线程按照相同的顺序请求资源。例如,有资源A、B、C,所有线程都必须先请求A,再请求B,最后请求C。这样就可以避免循环等待的情况。

- 采用资源分配图算法进行死锁检测和恢复

- 可以定期地检查系统中的资源分配情况,构建资源分配图。如果发现存在循环等待的情况(即死锁),可以通过终止一个或多个涉及死锁的线程,或者抢占一些线程的资源来恢复系统的正常运行。不过这种方式可能会导致部分线程的工作丢失,需要根据具体的应用场景谨慎使用。


http://www.ppmy.cn/ops/144410.html

相关文章

机器学习之归纳学习

归纳学习(Inductive Learning)是机器学习中的一个基础性概念,是指通过从有限的训练数据中总结出一般化的规则或模式,从而能够对新的、未知的数据进行预测或分类。归纳学习的核心思想是“从具体到抽象”,即通过对有限实…

基于Pytorch实现的说话人日志(说话人分离)

前言 VoiceprintRecognition_Pytorch 是博主开源的一款声纹识别框架,该框架支持EcapaTdnn、ResNetSE、ERes2Net、CAM等多种先进的声纹识别模型,也支持了MelSpectrogram、Spectrogram、MFCC、Fbank等多种数据预处理方法,支持AAMLoss、AMLoss、…

教育版idea及jetbrains全家桶免费使用

教育版idea及jetbrains全家桶免费使用 1. 还会有哪些惊喜呢?2. 赶快跟我一起抄作业吧2.1 先注册idea账号。2.2. 紧接着开启edu大门。2.3. 随后教育邮箱会收到一个验证链接。2.4. 接着用刚注册idea账号的浏览器打开链接验证。2.5. 最后 idea 直接登录刚才注册的idea账…

【Http,Netty,Socket,WebSocket的应用场景和区别】

Http,Netty,Socket,WebSocket的应用场景和区别 Http、Netty、Socket、WebSocket都是网络通信领域中的重要技术和工具,它们在应用场景和特性上有所区别。以下是对这四种技术和工具的应用场景及区别的详细分析: Http的…

本地摄像头视频流在html中打开

1.准备ffmpeg 和(rtsp-simple-server srs搭建流媒体服务器)视频服务器. 2.解压视频流服务器修改配置文件mediamtx.yml ,hlsAlwaysRemux: yes 3.双击运行服务器。 4,安装ffmpeg ,添加到环境变量。 5.查询本机设备列表 ffmpeg -list_devices true -f dshow -i d…

如何访问和修改字典中的值?

在Python中,字典是一种非常灵活的内置数据结构,用于存储键值对。每个键都与一个值相关联,这使得字典成为管理数据的强大工具。理解如何访问和修改字典中的值是掌握Python的关键技能之一。以下内容将详细介绍如何在Python中操作字典&#xff0…

从 PDF 到 Word:一个简单的 PythonGUI转换器

在日常工作中,我们经常需要将 PDF 文档转换为 Word 文件。幸运的是,Python 提供了很多强大的库,帮助我们实现这一功能。今天,我将与大家分享如何使用 wxPython 创建一个简单的图形用户界面(GUI)应用程序&am…

Sql注入(靶场)26-30关

第二十六关 这关将逻辑运算符,注释符以及空格给过滤了 我们先使用单引号进行闭合 这时我们查看源代码可以看到这一关过滤了很多字符 可以看到这里将or and / -- # 空格等字符都被注释了 空格被过滤了我们可以使用()来代替,and和or可以使用双写来绕过 …