From 8f841e62379d5be9b7eb79fd1eacf67d78cbc248 Mon Sep 17 00:00:00 2001 From: lionsoul2014 Date: Sat, 4 Apr 2026 17:54:05 +0800 Subject: [PATCH] add ConfigBuilder.setFairLock(boolean) to config whether ReentrantLock uses a fair lock --- binding/java/README.md | 11 ++++------- binding/java/README_zh.md | 9 ++++----- binding/java/pom.xml | 2 +- .../java/org/lionsoul/ip2region/service/Config.java | 6 +++++- .../lionsoul/ip2region/service/ConfigBuilder.java | 12 ++++++++++-- .../org/lionsoul/ip2region/service/Ip2Region.java | 4 ++-- 6 files changed, 26 insertions(+), 18 deletions(-) diff --git a/binding/java/README.md b/binding/java/README.md index 95b0a82..6109e85 100644 --- a/binding/java/README.md +++ b/binding/java/README.md @@ -10,7 +10,7 @@ org.lionsoul ip2region - 3.3.6 + 3.3.7 ``` @@ -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. diff --git a/binding/java/README_zh.md b/binding/java/README_zh.md index cf570c5..fa306f9 100644 --- a/binding/java/README_zh.md +++ b/binding/java/README_zh.md @@ -9,7 +9,7 @@ org.lionsoul ip2region - 3.3.6 + 3.3.7 ``` @@ -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 秒钟来等待尽量多的查询器归还。 diff --git a/binding/java/pom.xml b/binding/java/pom.xml index 31e2dc3..e3b6959 100644 --- a/binding/java/pom.xml +++ b/binding/java/pom.xml @@ -4,7 +4,7 @@ org.lionsoul ip2region - 3.3.6 + 3.3.7 jar ip2region diff --git a/binding/java/src/main/java/org/lionsoul/ip2region/service/Config.java b/binding/java/src/main/java/org/lionsoul/ip2region/service/Config.java index 0cb938c..3198988 100644 --- a/binding/java/src/main/java/org/lionsoul/ip2region/service/Config.java +++ b/binding/java/src/main/java/org/lionsoul/ip2region/service/Config.java @@ -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() { diff --git a/binding/java/src/main/java/org/lionsoul/ip2region/service/ConfigBuilder.java b/binding/java/src/main/java/org/lionsoul/ip2region/service/ConfigBuilder.java index addaec9..9732f30 100644 --- a/binding/java/src/main/java/org/lionsoul/ip2region/service/ConfigBuilder.java +++ b/binding/java/src/main/java/org/lionsoul/ip2region/service/ConfigBuilder.java @@ -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 diff --git a/binding/java/src/main/java/org/lionsoul/ip2region/service/Ip2Region.java b/binding/java/src/main/java/org/lionsoul/ip2region/service/Ip2Region.java index d55073b..3dffe68 100644 --- a/binding/java/src/main/java/org/lionsoul/ip2region/service/Ip2Region.java +++ b/binding/java/src/main/java/org/lionsoul/ip2region/service/Ip2Region.java @@ -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); } }