本节将全面讲解Lua中的线程实现、协程机制以及在Android平台下的多线程编程实践和优化技巧。
Lua本身不直接支持操作系统级线程,但可以通过以下方式实现多线程:
-- Lua原生协程(轻量级线程)
local co = coroutine.create(function() end)
-- 通过C扩展实现真线程(如LuaJIT的ffi)
local ffi = require("ffi")
ffi.cdef[[
int pthread_create(pthread_t*, const pthread_attr_t*, void*(*)(void*), void*);
]]
-- Android平台通过Java线程交互
local Thread = luajava.bindClass("java.lang.Thread")
注意: 原生Lua是单线程的,多线程需要依赖宿主环境或扩展库
-- 全局变量锁保护
local lock = require("lock")
function threadSafeFunc()
lock.acquire()
-- 操作共享资源
lock.release()
end
-- Android中的线程安全
local runOnUiThread = function(func)
activity.runOnUiThread(luajava.createProxy("java.lang.Runnable", {
run = func
}))
end
-- 使用LuaJIT的FFI调用pthread
local ffi = require("ffi")
ffi.cdef[[
typedef struct { int dummy; } pthread_t;
int pthread_create(pthread_t*, void*, void*(*)(void*), void*);
]]
local function threadFunc(arg)
print("线程运行:", ffi.string(arg))
return nil
end
local thr = ffi.new("pthread_t[1]")
local arg = ffi.new("char[?]", #"hello", "hello")
ffi.C.pthread_create(thr, nil, threadFunc, arg)
-- 创建Java线程
local Thread = luajava.bindClass("java.lang.Thread")
local Runnable = luajava.bindClass("java.lang.Runnable")
local task = Runnable{
run = function()
print("在Java线程中执行Lua代码")
-- 调用Lua函数
end
}
local thread = Thread(task)
thread:start()
-- 使用全局表+锁
sharedData = {
queue = {},
lock = require("lock")()
}
-- 生产者线程
function producer()
while true do
sharedData.lock:acquire()
table.insert(sharedData.queue, os.time())
sharedData.lock:release()
os.execute("sleep 1")
end
end
-- 消费者线程
function consumer()
while true do
sharedData.lock:acquire()
if #sharedData.queue > 0 then
print(table.remove(sharedData.queue, 1))
end
sharedData.lock:release()
end
end
-- Android中的Handler消息机制
local Handler = luajava.bindClass("android.os.Handler")
local Message = luajava.bindClass("android.os.Message")
local handler = Handler{
handleMessage = function(msg)
print("收到消息:", msg.obj)
end
}
-- 子线程发送消息
local thread = Thread{
run = function()
local msg = Message.obtain()
msg.obj = "来自子线程的数据"
handler:sendMessage(msg)
end
}
-- 安全的UI更新方法
function safeUpdateUI(view, data)
activity.runOnUiThread(luajava.createProxy("java.lang.Runnable", {
run = function()
view:setText(data)
view:invalidate()
end
}))
end
-- 异步任务示例
local AsyncTask = luajava.bindClass("android.os.AsyncTask")
local task = AsyncTask{
doInBackground = function(params)
-- 后台执行耗时操作
return "结果数据"
end,
onPostExecute = function(result)
-- 自动回到UI线程
textView:setText(result)
end
}
task:execute()
-- 使用Java线程池
local Executors = luajava.bindClass("java.util.concurrent.Executors")
local executor = Executors.newFixedThreadPool(4)
-- 提交任务
for i = 1, 10 do
executor:submit(luajava.createProxy("java.lang.Runnable", {
run = function()
print("执行任务"..i)
end
}))
end
-- 关闭线程池
executor:shutdown()
-- 简单的Lua锁实现
local lock = {
acquire = function(self)
while self.locked do
os.execute("sleep 0.01")
end
self.locked = true
end,
release = function(self)
self.locked = false
end,
locked = false
}
-- 使用示例
lock:acquire()
-- 临界区代码
lock:release()
-- 使用Java的同步机制
local Object = luajava.bindClass("java.lang.Object")
local monitor = Object()
-- 等待条件
function waitForCondition()
synchronized(monitor)
monitor:wait() -- 释放锁并等待
end
end
-- 通知条件
function notifyCondition()
synchronized(monitor)
monitor:notifyAll()
end
end
协程是Lua原生支持的轻量级线程,具有以下特点:
-- 创建协程
local co = coroutine.create(function()
print("协程开始")
coroutine.yield()
print("协程恢复")
end)
-- 执行协程
coroutine.resume(co) -- 输出"协程开始"
coroutine.resume(co) -- 输出"协程恢复"
local co = coroutine.create(function()
coroutine.yield("第一次yield")
return "结束"
end)
print(coroutine.status(co)) -- suspended
coroutine.resume(co) -- 返回true + "第一次yield"
print(coroutine.status(co)) -- suspended
coroutine.resume(co) -- 返回true + "结束"
print(coroutine.status(co)) -- dead
-- 通过yield和resume传递数据
local consumer = coroutine.create(function()
while true do
local data = coroutine.yield()
print("消费:", data)
end
end)
coroutine.resume(consumer) -- 启动协程
for i = 1, 3 do
coroutine.resume(consumer, "数据"..i) -- 输出"消费: 数据1"等
end
local co = coroutine.create(function()
print("协程收到:", coroutine.yield("第一次yield"))
return "最终结果"
end)
local _, msg = coroutine.resume(co) -- msg为"第一次yield"
print("主程序收到:", msg)
_, msg = coroutine.resume(co, "回复数据") -- 输出"协程收到: 回复数据"
print("主程序收到:", msg) -- "最终结果"
function producer()
return coroutine.create(function()
for i = 1, 3 do
coroutine.yield("产品"..i)
end
end)
end
function consumer(prod)
while true do
local _, product = coroutine.resume(prod)
if not product then break end
print("消费:", product)
end
end
consumer(producer())
function filter(prev_co)
return coroutine.create(function()
for value in prev_co do
if type(value) == "number" then
coroutine.yield(value * 2)
end
end
end)
end
function generator()
return coroutine.create(function()
coroutine.yield(1)
coroutine.yield("a")
coroutine.yield(2)
end)
end
local pipeline = filter(generator())
while true do
local _, val = coroutine.resume(pipeline)
if not val then break end
print(val) -- 输出2, 4
end
-- 将异步回调转为协程
function asyncTask(callback)
local co = coroutine.running()
callback(function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield()
end
-- 使用示例
local function httpGet(url, callback)
-- 模拟网络请求
Timer():schedule(1000, function()
callback("响应数据")
end)
end
coroutine.wrap(function()
local data = asyncTask(function(cb)
httpGet("https://example.com", cb)
end)
print("收到数据:", data) -- 1秒后输出
end)()
-- 安全的UI协程更新
function uiCoroutine(func)
coroutine.wrap(function()
-- 后台执行
local result = {func()}
-- 回到UI线程
activity.runOnUiThread(luajava.createProxy("java.lang.Runnable", {
run = function()
-- 处理结果
unpack(result)
end
}))
end)()
end
-- 使用示例
uiCoroutine(function()
local data = asyncTask(httpGet, "url") -- 后台网络请求
return function()
textView:setText(data) -- UI线程更新
end
end)
-- 简单的协程池实现
local coPool = {
pool = {},
get = function(self)
for i, co in ipairs(self.pool) do
if coroutine.status(co) == "dead" then
table.remove(self.pool, i)
elseif coroutine.status(co) == "suspended" then
return co
end
end
return coroutine.create(function() end)
end,
recycle = function(self, co)
table.insert(self.pool, co)
end
}
-- 使用示例
local co = coPool:get()
coroutine.resume(co, function()
print("任务执行")
end)
coPool:recycle(co)
-- 协程调用栈追踪
function printCoroutineStack(co)
print("协程栈追踪:", co)
local level = 1
while true do
local info = debug.getinfo(co, level)
if not info then break end
print(string.format("%s:%d in '%s'",
info.short_src, info.currentline, info.name or "?"))
level = level + 1
end
end
-- 使用示例
local co = coroutine.create(function()
local function inner()
printCoroutineStack(coroutine.running())
end
inner()
end)
coroutine.resume(co)
特性 | 协程 | 线程 |
---|---|---|
创建开销 | 极小(~400字节) | 较大(~1MB) |
切换成本 | 纳秒级 | 微秒级 |
并行性 | 协作式 | 抢占式 |
适用场景 | I/O密集型 | CPU密集型 |
-- 避免协程泄漏
local weakTable = setmetatable({}, {__mode = "v"})
function trackedCoroutine(f)
local co = coroutine.create(f)
weakTable[co] = true
return co
end
-- 定期检查泄漏
function checkLeaks()
for co in pairs(weakTable) do
if coroutine.status(co) == "dead" then
weakTable[co] = nil
end
end
print("活跃协程数:", tableCount(weakTable))
end