关于在java上使用lua脚本

Lua是一种小巧的脚本语言,现在经常被用于游戏中。

如果要在Java中使用Lua需要第三方库,如果搜索的话,一般搜到的都是[url=http://www.keplerproject.org/luajava/]LuaJava[/url]。LuaJava并不是一个纯Java的实现,它需要通过native方法调用C库,依赖于Lua 5.1。官网上可以下载到编译好的win32版LuaJava,其他平台的可以自己用源码进行编译。不幸的是它本身有一些bug,会导致JVM崩溃。而且LuaJava从2007年之后也不再更新了,没人维护。

除了LuaJava之外还有一些其他的Lua脚本引擎,比如[url=http://luaj.org/luaj/README.html]LuaJ[/url]。LuaJ是纯Java实现的Lua解释器,没有native方法,因此相对健壮一些,不会由于一些错误轻易的导致JVM crash,而且还支持JSR-223。

现在LuaJ的release版本是2.0.3,2这个系列的版本是有线程安全问题的。我们可以写段代码来试一下。

package net.szh;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class TestLuaj {

public static void main(String[] args) throws Exception {
int threadCount = 4;
final int runCount = 100000;
ExecutorService exec = Executors.newCachedThreadPool();
final CountDownLatch cdl = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
exec.execute(new Runnable() {

@Override
public void run() {
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("luaj");
try {
for (int i = 0; i < runCount; i++) {
engine.eval("local i = 0; assert(i)");
}
} catch (ScriptException e) {
e.printStackTrace();
} finally {
cdl.countDown();
}
}
});
}
cdl.await();
exec.shutdown();
}

}

执行后,有可能会出现如下的异常信息:

Exception in thread "pool-1-thread-3" java.lang.ArrayIndexOutOfBoundsException: -1
at org.luaj.vm2.LuaThread$CallStack.onReturn(Unknown Source)
at org.luaj.vm2.LuaClosure.execute(Unknown Source)
at org.luaj.vm2.LuaClosure.onInvoke(Unknown Source)
at org.luaj.vm2.LuaClosure.invoke(Unknown Source)
at org.luaj.vm2.script.LuaScriptEngine$CompiledScriptImpl.eval(Unknown Source)
at org.luaj.vm2.script.LuaScriptEngine.eval(Unknown Source)
at org.luaj.vm2.script.LuaScriptEngine.eval(Unknown Source)
at org.luaj.vm2.script.LuaScriptEngine.eval(Unknown Source)
at net.szh.TestLuaj$1.run(TestLuaj.java:27)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)

官方的jar包没把行号编译进去,我们可以自己打个jar包。

Exception in thread "pool-1-thread-3" java.lang.ArrayIndexOutOfBoundsException: -1
at org.luaj.vm2.LuaThread$CallStack.onReturn(LuaThread.java:345)
at org.luaj.vm2.LuaClosure.execute(LuaClosure.java:506)
at org.luaj.vm2.LuaClosure.onInvoke(LuaClosure.java:176)
at org.luaj.vm2.LuaClosure.invoke(LuaClosure.java:168)
at org.luaj.vm2.script.LuaScriptEngine$CompiledScriptImpl.eval(LuaScriptEngine.java:207)
at org.luaj.vm2.script.LuaScriptEngine.eval(LuaScriptEngine.java:111)
at org.luaj.vm2.script.LuaScriptEngine.eval(LuaScriptEngine.java:107)
at org.luaj.vm2.script.LuaScriptEngine.eval(LuaScriptEngine.java:95)
at net.szh.TestLuaj$1.run(TestLuaj.java:27)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)

对照源代码可以看到是因为内部共享了一个LuaFunction数组和数组索引的计数器,导致了此问题。

不过LuaJ已经有3.0版了,不过是beta版的。我第一次看到的时候是3.0-beta1,在3.0的描述中有提到对线程安全做了改进。用 3.0-beta1 跑一下上边的代码可以发现不再有异常抛出。这是一个较为可用的版本。

今年年初的时候,LuaJ发布了 3.0-beta2 版,试用了一下,发现有字符编码问题,可以跑下代码

package net.szh;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class TestLuaj {

public static void main(String[] args) throws Exception {
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("luaj");
engine.eval("--啦啦啦 local i = 0; assert(i)");
}

}

执行后,会出现如下的异常信息:

Exception in thread "main" javax.script.ScriptException: eval threw javax.script.ScriptException: load script: java.lang.ArrayIndexOutOfBoundsException: 32
at org.luaj.vm2.script.LuaScriptEngine.compile(LuaScriptEngine.java:94)
at org.luaj.vm2.script.LuaScriptEngine.eval(LuaScriptEngine.java:112)
at org.luaj.vm2.script.LuaScriptEngine.eval(LuaScriptEngine.java:106)
at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:247)
at net.szh.TestLuaj.main(TestLuaj.java:11)

我已经提了[url=https://sourceforge.net/p/luaj/bugs/24/]bug[/url],并且有人已经找到了问题所在。所以现在还是只有 3.0-beta1 相对可用。

--------------------
2014-10更新
现在已经有了3.0正式版,已经修复了UTF-8编码的bug。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值