add ConfigBuilder.setFairLock(boolean) to config whether ReentrantLock uses a fair lock

This commit is contained in:
lionsoul2014 2026-04-04 17:54:05 +08:00
parent d7b60f41e4
commit 8f841e6237
6 changed files with 26 additions and 18 deletions

View File

@ -10,7 +10,7 @@
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>3.3.6</version>
<version>3.3.7</version>
</dependency>
```
@ -29,6 +29,7 @@ final Config v4Config = Config.custom()
// .setCacheSliceBytes(int) // Set cache slice bytes, default is 50MiB
// .setXdbInputStream(InputStream) // Set v4 xdb file inputstream object
// .setXdbFile(File) // Set v4 xdb File object
// .setFairLock(boolean) // Set whether ReentrantLock uses a fair lock
.setXdbPath("ip2region v4 xdb path") // Set the path of v4 xdb file
.asV4(); // Specify as v4 configuration
@ -39,6 +40,7 @@ final Config v6Config = Config.custom()
// .setCacheSliceBytes(int) // Set cache slice bytes, default is 50MiB
// .setXdbInputStream(InputStream) // Set v6 xdb file inputstream object
// .setXdbFile(File) // Set v6 xdb File object
// .setFairLock(boolean) // Set whether ReentrantLock uses a fair lock
.setXdbPath("ip2region v6 xdb path") // Set the path of v6 xdb file
.asV6(); // Specify as v6 configuration
@ -61,12 +63,7 @@ ip2Region.close();
1. The API of this query service is concurrency-safe and supports both `IPv4` and `IPv6` addresses; the internal implementation will automatically distinguish them.
2. v4 and v6 configurations need to be created separately. You can set different cache policies for v4 and v6, or specify one of them as `null`, in which case IP address queries for that version will return `null`.
3. Please set a suitable number of searchers for `setSearchers` based on your project's concurrency. The default is 20. This value is fixed during runtime. Each query will borrow a searcher from the pool and return it after the query is completed. If the pool is empty when borrowing, it will wait until a searcher becomes available. The borrow lock is managed using `ReentrantLock`. You can also set the `Ip2Region` query service to use a fair lock as follows:
```java
final Ip2Region ip2region = Ip2Region.create(v4Config, v6Config, true);
```
3. Please set a suitable number of searchers for `setSearchers` based on your project's concurrency. The default is 20. This value is fixed during runtime. Each query will borrow a searcher from the pool and return it after the query is completed. If the pool is empty when borrowing, it will wait until a searcher becomes available. The borrow lock is managed using `ReentrantLock`. You can also call `ConfigBuilder.setFairLock(true)` to force the service to use a fair lock.
4. If the cache policy in the configuration is set to `Config.BufferCache` (i.e., `Full Memory Cache`), a single-instance memory searcher will be used by default. This implementation is natively concurrency-safe, and the number of searchers specified via `setSearchers` will be ignored.
5. If `close` is called while the `ip2region` searcher is providing service, it will wait for a maximum of 10 seconds by default to allow as many searchers as possible to be returned.

View File

@ -9,7 +9,7 @@
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>3.3.6</version>
<version>3.3.7</version>
</dependency>
```
@ -26,6 +26,7 @@ final Config v4Config = Config.custom()
// .setCacheSliceBytes(int) // 设置缓存的分片字节数,默认为 50MiB
// .setXdbInputStream(InputStream) // 设置 v4 xdb 文件的 inputstream 对象
// .setXdbFile(File) // 设置 v4 xdb File 对象
// .setFairLock() // 设置 ReentrantLock 是否使用公平锁
.setXdbPath("ip2region v4 xdb path") // 设置 v4 xdb 文件的路径
.asV4(); // 指定为 v4 配置
@ -36,6 +37,7 @@ final Config v6Config = Config.custom()
// .setCacheSliceBytes(int) // 设置缓存的分片字节数,默认为 50MiB
// .setXdbInputStream(InputStream) // 设置 v6 xdb 文件的 inputstream 对象
// .setXdbFile(File) // 设置 v6 xdb File 对象
// .setFairLock() // 设置 ReentrantLock 是否使用公平锁
.setXdbPath("ip2region v6 xdb path") // 设置 v6 xdb 文件的路径
.asV6(); // 指定为 v6 配置
@ -56,10 +58,7 @@ ip2Region.close();
##### `Ip2Region` 查询备注:
1. 该查询服务的 API 并发安全且同时支持 `IPv4``IPv6` 的地址,内部实现会自动判断。
2. v4 和 v6 的配置需要单独创建,可以给 v4 和 v6 设置使用不同的缓存策略,也可以指定其中一个为 `null` 则该版本的 IP 地址查询都会返回 `null`
3. 请结合您项目的并发数给 `setSearchers` 一个合适的查询器数量,默认为 20 个,这个值在运行过程中是固定的,每次查询会从池子里租借一个查询器来完成查询操作,查询完成后再归还回去,如果租借的时候池子已经空了则等待直到有可用的查询器来完成查询服务,租借的锁是使用的 `ReentrantLock` 来管理,也可以通过如下方式来设置 `Ip2Region` 查询服务使用公平锁:
```java
final Ip2Region ip2region = Ip2Region.create(v4Config, v6Config, true);
```
3. 请结合您项目的并发数给 `setSearchers` 一个合适的查询器数量,默认为 20 个,这个值在运行过程中是固定的,每次查询会从池子里租借一个查询器来完成查询操作,查询完成后再归还回去,如果租借的时候池子已经空了则等待直到有可用的查询器来完成查询服务,租借的锁是使用的 `ReentrantLock` 来管理,也可以通过调用 `ConfigBuilder.setFairLock(true)` 来配置查询服务使用公平锁:
4. 如果配置设置的缓存策略为 `Config.BufferCache``全内存缓存` 则默认会使用单实例的内存查询器,该实现天生并发安全,此时通过 `setSearchers` 指定的查询器数量无效。
5. 如果 `ip2region` 查询器在提供服务期间,调用 close 默认会最大等待 10 秒钟来等待尽量多的查询器归还。

View File

@ -4,7 +4,7 @@
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>3.3.6</version>
<version>3.3.7</version>
<packaging>jar</packaging>
<name>ip2region</name>

View File

@ -39,13 +39,16 @@ public class Config {
public final int searchers;
// force ReenTrantLock to use fair Lock
public final boolean fairLock;
// config builder
public static ConfigBuilder custom() {
return new ConfigBuilder();
}
protected Config(int cachePolicy, Version ipVersion, File xdbFile,
Header header, byte[] vIndex, LongByteArray cBuffer, int searchers) throws IOException, XdbException {
Header header, byte[] vIndex, LongByteArray cBuffer, int searchers, boolean fairLock) throws IOException, XdbException {
this.cachePolicy = cachePolicy;
this.ipVersion = ipVersion;
@ -62,6 +65,7 @@ public class Config {
}
this.searchers = searchers;
this.fairLock = fairLock;
}
@Override public String toString() {

View File

@ -37,6 +37,9 @@ public class ConfigBuilder {
// searchers
private int searchers = 20;
// fair lock
private boolean fairLock = false;
public ConfigBuilder() {}
public ConfigBuilder(String xdbPath) {
@ -76,6 +79,11 @@ public class ConfigBuilder {
return this;
}
public ConfigBuilder setFairLock(boolean fairLock) {
this.fairLock = fairLock;
return this;
}
private Config build(Version ipVersion) throws IOException, XdbException, InvalidConfigException {
if (xdbInputStream == null) {
// everyting is fine
@ -94,7 +102,7 @@ public class ConfigBuilder {
final Header header = Searcher.loadHeaderFromBuffer(cBuffer);
// create the config without xdbFile and vIndex
return new Config(cachePolicy, ipVersion, null, header, null, cBuffer, searchers);
return new Config(cachePolicy, ipVersion, null, header, null, cBuffer, searchers, fairLock);
}
// load the header and the cache buffer
@ -122,7 +130,7 @@ public class ConfigBuilder {
final LongByteArray cBuffer = cachePolicy == Config.BufferCache ? Searcher.loadContent(raf, cacheSliceBytes) : null;
raf.close();
return new Config(cachePolicy, ipVersion, xdbFile, header, vIndex, cBuffer, searchers);
return new Config(cachePolicy, ipVersion, xdbFile, header, vIndex, cBuffer, searchers, fairLock);
}
// build the final #Config instance for IPv4

View File

@ -81,7 +81,7 @@ public class Ip2Region {
this.v4Pool = null;
} else {
this.v4InMemSearcher = null;
this.v4Pool = new SearcherPool(v4Config);
this.v4Pool = new SearcherPool(v4Config, v4Config.fairLock);
}
if (v6Config == null) {
@ -93,7 +93,7 @@ public class Ip2Region {
this.v6Pool = null;
} else {
this.v6InMemSearcher = null;
this.v6Pool = new SearcherPool(v6Config);
this.v6Pool = new SearcherPool(v6Config, v6Config.fairLock);
}
}