Lua 5.4.8 + Java 双向互调引擎。在 Lua 里直接调用任何 Java 类库,在 Java 里执行 Lua 脚本。
支持异步多线程(轮询/回调双模式)、动态代理、批量高性能数学运算,架构清晰,升级 Lua 仅需替换目录。
完整 API 文档见
docs/目录:APIs.md · AgentV2.md · Java4Lua.md · Lua4Java.md
LuaJavaNE/
├── lua/ # Lua 官方源码(解压即用,无需任何修改)
│ └── lua-5.4.8/
├── native/ # C 代码
│ ├── jni/ # JNI 桥接
│ └── lualib/ # 自定义 Lua 库(java / clac / async / utils / gc)
├── java/src/com/luajava/ # Java 源码
├── test/ # JUnit 测试
├── lib/ # 第三方 jar
├── docs/ # 文档
├── examples/ # 示例脚本
├── CMakeLists.txt # C 构建配置
├── Makefile # 主构建文件
└── luaj.sh # 启动脚本
git clone https://github.com/npp-zep/LuaJavaNE.git
cd LuaJavaNE
make # 完整构建(C + Java)
# 或者使用 Ninja 加速 C 编译:
make ninja # 需要安装 ninja-build构建完成后运行 REPL:
./luaj.sh从 Releases 下载 luajava.jar 和 luajava.so,放在同一目录:
java -Dluajava.library.path=./luajava.so -jar luajava.jar本项目 Lua 源码完全保持原样,不进行任何修改。升级到新版本只需两步:
-
删除旧版本目录:
rm -rf lua/lua-5.4.8
-
下载新版本并解压到 lua/ 目录:
wget https://lua.org/ftp/lua-5.5.0.tar.gz tar xzf lua-5.5.0.tar.gz -C lua/
构建系统会自动识别 lua/lua-* 目录,无需改动任何代码或配置。
LuaRuntime L = new LuaRuntime();
L.doString("function add(a, b) return a + b end");
Object result = L.callFunction("add", 3, 5); // 8
LuaFunctionObj fn = L.compile("return function(x) return x * 2 end");
LuaFunctionObj doubler = (LuaFunctionObj) fn.call();
doubler.call(21); // 42
fn.destroy(); doubler.destroy();
L.close();local java = require("java")
local String = java.import("java.lang.String")
local s = String:new("Hello World")
print(s:length()) -- 11
print(s:substring(0, 5)) -- Hello@LuaModule("math")
class MyMath {
@LuaFunction public int add(int a, int b) { return a + b; }
@LuaFunction("multiply") public int mul(int a, int b) { return a * b; }
}LuaRuntime L = new LuaRuntime();
L.registerModule(new MyMath());
L.doString("print(math_add(3, 5))"); -- 8
L.doString("print(math_multiply(6, 7))"); -- 42用 Lua 表实现 Java 接口:
local Runnable = java.import("java.lang.Runnable")
local handler = { run = function(self) print("Hello from Lua!") end }
local proxy = java.createProxy({"java.lang.Runnable"}, handler)
java.import("java.lang.Thread"):new(proxy):start()Agent v2 提供强大的异步执行能力,所有任务在后台线程池中运行,结果通过 Promise 机制回传主线程。
local id = java.promise()
java.runAsync(id, "java.lang.Integer", "parseInt", "42")
repeat local done, result = java.checkPromise(id) until done
print(result) -- 42local String = java.import("java.lang.String")
local s = String:new("Hello World")
local id = java.promise()
java.runAsyncObj(id, s, "length")
repeat local done, result = java.checkPromise(id) until done
print(result) -- 11local id = java.promise()
java.runAsync(id, "java.lang.String", "new", "Hello")
repeat local done, oid = java.checkPromise(id) until done
local obj = java.getObject(oid) -- 获取 userdata
print(obj:length()) -- 5local s = String:new("a,b,c")
local id = java.promise()
java.runAsyncObj(id, s, "split", ",")
repeat local done, a, b, c = java.checkPromise(id) until done
print(a, b, c) -- a b c异步任务中抛出的异常会被捕获并作为字符串返回,消息格式为
类名.方法 -> 异常类型: 消息(包含根因信息):
java.runAsync(id, "java.lang.NonExistent", "foo", "")
-- checkPromise 返回: "java.lang.NonExistent.foo -> ClassNotFoundException: java.lang.NonExistent"同步调用(Java 侧)的错误则抛出结构化异常,全部继承 RuntimeException,对既有
catch (RuntimeException) 完全向后兼容:
LuaRuntimeError—— Lua 执行期错误LuaSyntaxError—— Lua 编译期语法错误(LuaRuntimeError的子类)JavaInvocationError—— Lua 调用已注册 Java 方法失败TypeConversionError—— Lua ⇄ Java 参数类型转换失败
除了轮询 checkPromise,还可以注册完成回调,任务完成时由后台线程自动调用:
local id = java.promise()
java.runAsync(id, "java.lang.Integer", "parseInt", "42")
java.onComplete(id, function(err, result)
if err then print("失败:", err) else print("结果:", result) end -- 42
end)- 回调签名:
callback(err, result...),err == nil表示成功。 - 回调在后台工作线程执行,应快速返回;耗时的重活请再次
runAsync提交。 - 更多异步 API 细节见
docs/AgentV2.md。
主线程轮询等待期间,用 java.yield(ms) 短暂释放 Lua 锁(默认 10ms),让后台回调/代理线程有机会执行 Lua 代码,避免持锁等待导致死锁(Thread.sleep 不释放锁):
local done = false
java.onComplete(id, function(err, result) done = true end)
while not done do java.yield(10) endclac 模块提供了完整的 C 标准数学函数,以及批量数组运算(83 倍加速)。
local clac = require("clac")
print(clac.pi()) -- 3.1415926535898
print(clac.sin(1.57)) -- 0.99999968293183
print(clac.erf(1.0)) -- 0.84270079294971
print(clac.tgamma(5.0)) -- 24.0local a = clac.array(10000)
local b = clac.array(10000)
-- 填充数据...
local c = clac.batch_add(a, b) -- 直接在 C 内存中完成,比 Lua 表循环快 83 倍
local d = clac.batch_sin(a) -- 逐元素求正弦| 分类 | 函数 |
|---|---|
| 四则运算 | batch_add, batch_sub, batch_mul, batch_div |
| 三角函数 | batch_sin, batch_cos, batch_tan, batch_asin, batch_acos, batch_atan |
| 双曲函数 | batch_sinh, batch_cosh, batch_tanh, batch_asinh, batch_acosh, batch_atanh |
| 指数对数 | batch_exp, batch_exp2, batch_expm1, batch_log, batch_log10, batch_log2, batch_log1p |
| 取整 | batch_floor, batch_ceil, batch_round, batch_trunc, batch_rint |
| 特殊函数 | batch_erf, batch_erfc, batch_tgamma, batch_lgamma |
| 其他 | batch_sqrt, batch_cbrt, batch_pow, batch_atan2, batch_hypot |
utils 模块提供高精度时间和休眠功能,适用于性能测量和精确控制。
local utils = require("utils")
-- 高精度时间(秒,浮点数,纳秒级精度)
local t = utils.ns_time()
-- 单调时间(不受系统时间调整影响)
local mt = utils.monotonic_time()
-- Unix 时间戳(秒,整数)
local ts = utils.timestamp()
-- Unix 时间戳(毫秒,整数)
local ts_ms = utils.timestamp_ms()-- 休眠指定秒数(支持小数)
utils.sleep(0.5) -- 500ms
-- 休眠毫秒
utils.sleep_ms(100)
-- 休眠微秒
utils.sleep_us(1000) -- 1ms
-- 休眠纳秒
utils.sleep_ns(1000000) -- 1mslocal timer = utils.timer()
-- 获取从开始到现在的总时间
local elapsed = timer:elapsed()
-- 获取从上一次 lap 到现在的时间
local lap = timer:lap()
-- 重置计时器
timer:reset()local function benchmark_sleep(count, duration_ms)
local t = utils.timer()
for i = 1, count do
utils.sleep_ms(duration_ms)
end
local total = t:elapsed()
local expected = count * duration_ms / 1000.0
local error_pct = (total - expected) / expected * 100
return total, error_pct
end
local total, err = benchmark_sleep(10, 10)
print(string.format("10次*10ms: 实际=%.3fs, 误差=%.1f%%", total, err))gc 模块提供跨语言对象引用管理,支持强引用和弱引用。
local gc = require("gc")
local String = java.import("java.lang.String")
local s = String:new("Hello")
-- 创建强引用
local ref = gc.hold(s)
-- 获取引用对象
local obj = gc.get(ref) -- 返回 userdata
-- 检查引用是否存在
if gc.exists(ref) then
print("Object is still alive")
end
-- 释放引用
gc.release(ref)
-- 弱引用(不阻止 GC)
local weak_ref = gc.holdWeak(s)luaj # 启动交互式 REPL
luaj script.lua # 执行脚本文件
luaj -e "print(1+1)" # 执行一行代码
luaj -v # 版本信息(含编译器版本)
luaj -h # 帮助| 快捷键 | 功能 |
|---|---|
| ↑ ↓ | 浏览历史 |
| Ctrl+R | 搜索历史 |
| \q | 退出 |
| = 1+2 | 打印表达式结果 |
| help / copyright / license | 查看信息 |
| Lua | Java 方向 |
|---|---|
| integer | Integer / int 双向 |
| number | Double / double 双向 |
| string | String 双向 |
| boolean | Boolean 双向 |
| nil | null / void 返回 |
| userdata | Java 对象 双向 |
| function | LuaFunctionObj Lua → Java |
| table | LuaTable(Lua → Java 惰性引用) |
| Map / List / Collection(Java 返回) | 惰性容器 userdata(读取/遍历/写回/追加,可存 Lua 函数读回可调用) |
| 方法 | 说明 |
|---|---|
| LuaRuntime() | 创建 Lua 虚拟机 |
| doString(script) | 执行 Lua 代码 |
| doFile(path) | 执行 Lua 文件 |
| callFunction(name, ...) | 调用全局函数,返回第一个值 |
| callFunctionMultiple(name, ...) | 调用全局函数,返回所有值 |
| compile(code) | 编译为 LuaFunctionObj |
| registerModule(obj) | 注册带 @LuaModule 注解的对象 |
| close() | 关闭虚拟机 |
| 函数 | 说明 |
|---|---|
| java.import("类名") | 导入 Java 类 |
| 类:new(...) | 调用构造方法 |
| 对象:方法(...) / 对象(...) | 调用实例方法;对象可直接调用(__call,调用其 call 方法) |
| 类.静态方法(...) / 类:静态方法(...) | 调用静态方法(冒号形式自动剥离类 self 参数) |
| java.createProxy({接口...}, 表) | Lua 表实现 Java 接口 |
| java.newArray("类型", 大小) | 创建 Java 数组 |
| java.import("com.luajava.LuaTable") | Java 侧以 LuaTable 接收 Lua 表(活引用,见 docs/Java4Lua.md 第 8 节) |
| 容器(Java 返回的 Map/List) | JavaTable 惰性容器:读取/遍历/写回/#,l[#l+1]=v 追加,可存 Lua 函数读回可调用 |
| java.promise() | 创建异步 Promise |
| java.runAsync(id, class, method, args...) | 异步调用静态方法 |
| java.runAsyncObj(id, obj, method, args...) | 异步调用实例方法 |
| java.checkPromise(id) | 轮询 Promise 结果 |
| java.onComplete(id, callback) | 注册完成回调(事件驱动) |
| java.complete(id, value) | 手动完成一个 Promise |
| java.await(id) | 协程内阻塞等待 Promise 完成 |
| java.yield(ms) | 释放 Lua 锁等待,让后台回调执行 |
| java.getObject(id) | 获取异步构造的对象 |
| java.toString(obj) | 获取对象的字符串表示 |
| java.store(key, value) | 跨 Lua 状态存储值 |
| java.fetch(key) | 读取跨状态存储值 |
| java.listall() | 列出所有存储键值对(返回 key -> value 表) |
| java.deleteStore(key) | 删除跨状态存储键 |
| 函数 | 说明 |
|---|---|
| clac.array(n) | 创建 ClacArray |
| clac.pi() / clac.e() | 数学常量 |
| clac.sin(x) / clac.cos(x) / ... | 标量数学函数 |
| clac.batch_add(a, b) / batch_sub(...) | 批量四则运算 |
| clac.batch_sin(a) / batch_cos(a) / ... | 批量一元函数 |
| clac.batch_pow(a, b) / batch_atan2(a, b) / ... | 批量二元函数 |
| clac.random() / clac.seed() | 随机数生成 |
| 函数 | 说明 |
|---|---|
| utils.ns_time() | 高精度时间(秒) |
| utils.monotonic_time() | 单调时间(秒) |
| utils.timestamp() | Unix 时间戳(秒) |
| utils.timestamp_ms() | Unix 时间戳(毫秒) |
| utils.sleep(sec) | 休眠指定秒数 |
| utils.sleep_ms(ms) | 休眠指定毫秒数 |
| utils.sleep_us(us) | 休眠指定微秒数 |
| utils.sleep_ns(ns) | 休眠指定纳秒数 |
| utils.timer() | 创建计时器对象 |
| 函数 | 说明 |
|---|---|
| gc.hold(obj) | 创建强引用 |
| gc.holdWeak(obj) | 创建弱引用 |
| gc.get(ref) | 获取引用对象 |
| gc.release(ref) | 释放引用 |
| gc.exists(ref) | 检查引用是否存在 |
| gc.count() | 获取引用数量 |
| gc.list() | 列出所有引用 ID |
| gc.clear() | 清除所有引用 |
要求:JDK 17+、CMake 3.14+、GCC/Clang、pthread。
git clone https://github.com/npp-zep/LuaJavaNE.git
cd LuaJavaNE
make # 标准构建
# 或
make ninja # Ninja 快速构建
make test # 运行测试- 常规签名匹配失败时自动回退反射调用,支持任意返回类型(如
java.math);极少数高度动态的重载仍可能不精确 - Termux/Android 环境下线程数上限约 200(受系统限制)
git clone git@github.com:npp-zep/LuaJavaNE.git
cd LuaJavaNE
git checkout -b feature/my-feature
# 修改代码
make && make test
git commit -m "Description"
git push origin feature/my-feature
# 在 GitHub 上提 Pull Request本项目主体采用 MIT License。
- Lua 5.4.8 — MIT License
- JLine 3 — BSD-3-Clause License
- Sleef — Boost Software License 1.0
- JUnit 5 — EPL-1.0(仅用于测试,不包含在发布包中)
作者: npp-zep