每日一记 - 3.10

文章讨论了Java中的wait和sleep方法的区别,Kafka的优点和缺点,线程池的工作流程及其大小调整,AQS在可重入锁中的作用,以及SpringCloud和SpringBoot的区别。还涉及到了数据一致性、设计模式和线程同步策略。

八股相关


一、具体问题

(Java 语言)1. wait 和 sleep 方法的区别?

(Kafka)2. Kafka 有哪些优点/缺点?

(JUC)3. 线程池的运行流程是怎么样的?

(JUC)4. 线程池如果设置过大了,会怎么样?

(JUC)5. 线程池要是没有关闭,那么一直运行下去,他接下来会一直运行吗,还是自动关闭?

(JUC)6. 你自己如何根据业务调整线程池的大小的,判断依据在哪?

(Redis)7. 如何保障本地缓存和 redis 实现数据一致性?

(设计模式)8. 什么是享元模式?

(JUC)9. 什么是 AQS?它有什么作用?如何使用?

(JUC)10. 可重入锁的底层加锁和释放锁是怎么样的呢?

(Spring)11. Spring Cloud 与 Spring Boot 区别是什么?


二、参考答案

(Java 语言)1. wait 和 sleep 方法的区别?

wait 和 sleep 方法区别体现在:

  1. wait 方法属于 Object 类的方法。在调用 wait 方法前,需要获取内部的监视器锁。因此,需要在同步代码块中使用;sleep 方法属于 Thread 类的方法。可以在任何地方使用。

  2. wait 方法在调用时,会释放持有的锁;而 sleep 方法在调用时,不会释放持有的锁。

  3. wait 方法在调用时,会一直等待直到被唤醒;而 sleep 方法在调用时,只会暂停一段时间。

(Kafka)2. Kafka 有哪些优点/缺点?

Kafka 优点包括:

  1. 高性能:Kafka 提供了高吞吐量和低延时的消息传递能力,可以支持大规模的数据处理。
  2. 可扩展:Kafka 是一个分布式系统,可以扩展到多结点。
  3. 可靠性:Kafka 提供多种备份机制,可以保证消息传递到可靠性。

Kafka 缺点包括:

  1. 处理存在延时。由于 Kafka 批量处理消息,在高峰期可能会存在延时情况。
  2. 仅支持统一分区内的消息有序,无法实现全局消息有序。
  3. Kafka 依赖于 Zookeeper 来管理集群的状态和元数据。当 Zookeeper 配置出错时,Kafka 受到很大的影响。

(JUC)3. 线程池的运行流程是怎么样的?

线程池的运行流程包括:

  • 第一,创建线程池,初始化线程池中空闲线程的数量。
  • 第二,提交任务,通过程序分配任务到线程池中。
  • 第三,执行任务,由线程池分配空闲的线程来执行任务。
  • 第四,结束任务,当线程执行完任务后,会回归到线程池中。
  • 最后,销毁线程池,当程序不再使用线程池时,可以调用销毁方法来销毁线程池。

下面指的线程池是 ThreadPoolExecutor 类。

提交任务: 调用线程池的 execute() 方法。

销毁方法: 调用线程池的 shutdown() 方法。

(JUC)4. 线程池如果设置过大了,会怎么样?

线程池设置过大,可能会出现多种问题,例如:

  • 占用内存资源。当线程池设置过大,但是执行任务的线程很少时,会造成空闲线程过大,存在资源浪费。
  • 线程切换花销。当线程池设置过大,会造成线程切换的频率相较而言更加频繁,造成花销增大。
  • 导致系统不稳定。当线程池设置过大,线程数量增多后,可能会因为线程之间的资源竞争,导致死锁。

(JUC)5. 线程池要是没有关闭,那么一直运行下去,他接下来会一直运行吗,还是自动关闭?

线程池要是没有被关闭,这个线程池对象在方法调用结束后,JVM 会回收它占用的内存资源。

但是,线程池中创建的线程将一直存在,除非在线程池对象被回收前调用它的销毁方法 shutdown

或者是等待 JVM 被关闭后。

(JUC)6. 你自己如何根据业务调整线程池的大小的,判断依据在哪?

我的业务中没有使用到线程池,但是使用了到线程池中的本地线程类 ThreadLocal

使用这个类的目的是用于创建线程的副本,主要是用于保存用户的登录信息,方便用户登录状态的查询。

并且,在多线程环境下,业务方法访问到的是所处线程下的用户信息,比较方便。

(Redis)7. 如何保障本地缓存和 redis 实现数据一致性?

本地缓存和 Redis 实现数据的一致性,可以通过中心化和去中心化方式来保障。

  • 对于中心化方式,就是将缓存管理的职责交给中心节点负责,同时随时进行数据的同步。
    • 但是它的缺点是,当中心节点故障时,导致整个系统瘫痪。
  • 对于去中心化方式,每个节点都可以缓存相同的数据,然后通过通信协议来同步缓存数据。

用于同步的通信协议有哪些?

包括 Gossip 协议、P2P 协议、Zookeeper 协议等等。

类似问题:如何保障 Redis 缓存和数据库中数据一致性?

数据一致性的保障可以分为「读、写操作」进行分析:

  1. 对于读操作
    • 如果数据在缓存中存在,则从缓存直接读出。
    • 如果数据在缓存中不存在,先从数据库中读出,再缓存在 Redis 中。
  2. 对于写数据
    • 如果缓存中不存在,和读的情况一致。
    • 如果缓存中存在,先写入 Redis 中,同时标记为脏数据。当这些数据要被移除时,才写回数据库。

(设计模式)8. 什么是享元模式?

享元模式是设计模式的一种,它的作用是减少创建对象的数据,来提高性能的内存的利用率。

这个模式的核心是 对象的共享,而不是每一次需要一个新对象时都创建一个新的实例。

(JUC)9. 什么是 AQS?它有什么作用?如何使用?

AQS(Abstract Queued Synchronizer,抽象队列同步器)是 JUC 包下的一个组件,它主要用于线程之间的同步。

它底层的思想是使用一个先进先出的队列来管理线程之间的资源竞争。

所有等待访问共享资源的线程都将被加入到这个队列中,并通过 CAS 操作获取等待资源的访问权。

**可重入锁(ReentrantLock)**底层加锁和释放锁主要是通过 AQS 实现的。

复习:什么是 CAS?

CAS 是一种 乐观锁机制,它使用原子操作对某个内存位置的值进行比较和修改。

当这个内存位置的值与预期值相等时,才会将该位置的值更新为新值,否则操作失败。

(JUC)10. 可重入锁的底层加锁和释放锁是怎么样的呢?

可重入锁的底层维护了一个 AQS 内部对象。

当可重入锁调用加锁 lock 方法时,会调用底层 AQS 的 tryAquire 方法。这个方法会读取同步器的状态。

  • 如果同步器的状态为 0,表示当前线程可以获取锁,然后将同步器状态设置为 1。
  • 如果同步器的状态不为 0,表示当前线程已经持有锁,同时增加“加锁”的这个状态。

当可重入锁调用释放锁 unlock 方法时,会调用底层 AQS 的 tryRelease 方法。

这个方法的实现过程与上锁的方法,在逻辑上是一个逆过程。同时,AQS 上锁和释放锁过程中都使用了 CAS 锁。

(Spring)11. Spring Cloud 与 Spring Boot 区别是什么?

Spring Boot 是一个用于构建基于 Spring 的应用程序的快速开发框架,使得开发人员可以快速搭建应用程序。

Spring Cloud 则是一组分布式系统开发框架,它基于 Spring Boot,提供了许多分布式系统所需的功能。

总的来说,Spring Boot 主要用于构建独立的 Spring 应用程序,而 Spring Cloud 则用于构建分布式系统

它在 Spring Boot 的基础上提供了分布式系统所需的各种功能和工具。


三、今日感悟

今天八股主要看了 JUC 相关,之前一直疑惑什么是 AQS,原来本质上就是一个用于同步的工具,而且它就被可重入锁所使用。还顺带看了下可重入锁的源码,还挺有意思的。就酱!

--------------------------------------------------------------------------- FileNotFoundError Traceback (most recent call last) Cell In[23], line 5 2 import numpy as np 4 # 加载数据 ----> 5 data = pd.read_csv('asset_data.csv') 7 # 检查数据集 8 print(data.head()) File /opt/conda/envs/anaconda-2024.02-py310/lib/python3.10/site-packages/pandas/io/parsers/readers.py:948, in read_csv(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, date_format, dayfirst, cache_dates, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, doublequote, escapechar, comment, encoding, encoding_errors, dialect, on_bad_lines, delim_whitespace, low_memory, memory_map, float_precision, storage_options, dtype_backend) 935 kwds_defaults = _refine_defaults_read( 936 dialect, 937 delimiter, (...) 944 dtype_backend=dtype_backend, 945 ) 946 kwds.update(kwds_defaults) --> 948 return _read(filepath_or_buffer, kwds) File /opt/conda/envs/anaconda-2024.02-py310/lib/python3.10/site-packages/pandas/io/parsers/readers.py:611, in _read(filepath_or_buffer, kwds) 608 _validate_names(kwds.get("names", None)) 610 # Create the parser. --> 611 parser = TextFileReader(filepath_or_buffer, **kwds) 613 if chunksize or iterator: 614 return parser File /opt/conda/envs/anaconda-2024.02-py310/lib/python3.10/site-packages/pandas/io/parsers/readers.py:1448, in TextFileReader.__init__(self, f, engine, **kwds) 1445 self.options["has_index_names"] = kwds["has_index_names"] 1447 self.handles: IOHandles | None = None -> 1448 self._engine = self._make_engine(f, self.engine) File /opt/conda/envs/anaconda-2024.02-py310/lib/python3.10/site-packages/pandas/io/parsers/readers.py:1705, in TextFileReader._make_engine(self, f, engine) 1703 if "b" not in mode: 1704 mode += "b" -> 1705 self.handles = get_handle( 1706 f, 1707 mode, 1708 encoding=self.options.get("encoding", None), 1709 compression=self.options.get("compression", None), 1710 memory_map=self.options.get("memory_map", False), 1711 is_text=is_text, 1712 errors=self.options.get("encoding_errors", "strict"), 1713 storage_options=self.options.get("storage_options", None), 1714 ) 1715 assert self.handles is not None 1716 f = self.handles.handle File /opt/conda/envs/anaconda-2024.02-py310/lib/python3.10/site-packages/pandas/io/common.py:863, in get_handle(path_or_buf, mode, encoding, compression, memory_map, is_text, errors, storage_options) 858 elif isinstance(handle, str): 859 # Check whether the filename is to be opened in binary mode. 860 # Binary mode does not support 'encoding' and 'newline'. 861 if ioargs.encoding and "b" not in ioargs.mode: 862 # Encoding --> 863 handle = open( 864 handle, 865 ioargs.mode, 866 encoding=ioargs.encoding, 867 errors=errors, 868 newline="", 869 ) 870 else: 871 # Binary mode 872 handle = open(handle, ioargs.mode) FileNotFoundError: [Errno 2] No such file or directory: 'asset_data.csv'
最新发布
06-17
看起来你在尝试加载名为 `asset_data.csv` 的文件时遇到了 `FileNotFoundError`,这意味着当前目录下没有找到该文件。有几种解决方法可以确保你能够成功加载数据: 1. **确认文件路径**:确保 `asset_data.csv` 文件确实存在于你指定的路径中。你可以提供文件的完整路径,例如 `/path/to/your/file/asset_data.csv`。 2. **下载示例数据**:如果你没有现成的数据文件,可以使用公开的金融数据API(如 `yfinance`)来获取数据。这里我们使用 `yfinance` 来获取股票数据作为示例。 3. **检查工作目录**:确保你在正确的目录中运行代码。你可以使用 `os.getcwd()` 检查当前的工作目录,并使用 `os.chdir()` 更改工作目录。 下面是一个使用 `yfinance` 获取股票数据并执行所需步骤的完整示例代码。我们将以苹果公司(AAPL)的股票为例。 ### 使用 `yfinance` 获取数据 首先,安装 `yfinance` 包(如果尚未安装): ```bash !pip install yfinance ``` 然后,运行以下代码: ```python import pandas as pd import numpy as np import yfinance as yf # 使用 yfinance 获取数据 ticker = 'AAPL' # 你可以选择其他股票代码 start_date = '2018-01-01' end_date = '2023-01-01' # 下载数据 data = yf.download(ticker, start=start_date, end=end_date) # 检查数据集 print(data.head()) # 确保数据按日期排序 data = data.sort_index() # 显示前几行数据以确认 print(data.head()) # 如果你需要手动加载CSV文件,请确保路径正确 # data = pd.read_csv('path/to/your/file/asset_data.csv') # data['Date'] = pd.to_datetime(data['Date']) # data.set_index('Date', inplace=True) # data = data.sort_index() ``` ### 步骤 2:创建时间窗口特征 计算 `Volume` 的 30 日移动平均值 (`rolling_mean_vol`) 和 30 日移动标准差 (`rolling_std_vol`)。 ```python # 计算 30 日滚动平均交易量和标准差 data['rolling_mean_vol'] = data['Volume'].rolling(window=30, min_periods=1).mean() data['rolling_std_vol'] = data['Volume'].rolling(window=30, min_periods=1).std() # 显示前几行数据以确认 print(data[['Volume', 'rolling_mean_vol', 'rolling_std_vol']].head()) ``` ### 步骤 3:创建价格波动率特征 计算每日的最高价与最低价之差 (`High - Low`),并将其标准化为当日收盘价的百分比,命名为 `daily_volatility`。 ```python # 计算每日价格波动率 data['daily_volatility'] = (data['High'] - data['Low']) / data['Close'] * 100 # 显示前几行数据以确认 print(data[['High', 'Low', 'Close', 'daily_volatility']].head()) ``` ### 步骤 4:识别“交易量异常”的交易日 根据给定的条件,筛选出所有“交易量异常”的日期: 1. 当日交易量超过其自身 30 日移动平均交易量的 3 个标准差以上。 2. 当日的 `daily_volatility` 位于历史数据(整个数据集)的前 95% 分位数之上。 ```python # 计算 daily_volatility 的 95% 分位数 volatility_95th_percentile = data['daily_volatility'].quantile(0.95) # 定义交易量异常的条件 data['is_anomalous_volume'] = ( (data['Volume'] > data['rolling_mean_vol'] + 3 * data['rolling_std_vol']) & (data['daily_volatility'] > volatility_95th_percentile) ) # 筛选出交易量异常的日期 anomalous_dates = data[data['is_anomalous_volume']].index # 显示交易量异常的日期 print("交易量异常的日期:") print(anomalous_dates) # 显示这些日期的详细信息 print("\n交易量异常的日期及其详情:") print(data[data['is_anomalous_volume']]) ``` ### 总结 通过上述步骤,我们已经成功识别出交易量出现“异常放”的交易日。具体实现了以下功能: 1. **加载数据并设置日期索引**:确保数据的日期格式正确,并按日期排序。 2. **创建时间窗口特征**:计算了 30 日滚动平均交易量和标准差。 3. **创建价格波动率特征**:计算了每日的价格波动率。 4. **识别交易量异常的交易日**:根据设定的条件筛选出异常日期,并展示了这些日期的详细信息。 如果你有实际的数据文件,请确保文件路径正确。如果有更多问题或需要进一步的帮助,请随时告知!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值